Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 99 additions & 3 deletions src/it/java/io/weaviate/integration/DataITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.api.collections.data.Reference;
import io.weaviate.client6.v1.api.collections.query.Metadata;
import io.weaviate.client6.v1.api.collections.query.QueryMetadata;
import io.weaviate.client6.v1.api.collections.query.QueryReference;
import io.weaviate.client6.v1.api.collections.vectorindex.Hnsw;
import io.weaviate.client6.v1.api.collections.vectorizers.NoneVectorizer;
Expand Down Expand Up @@ -45,8 +46,10 @@ public void testCreateGetDelete() throws IOException {
.returnProperties("name")
.returnMetadata(Metadata.ID, Metadata.VECTOR));

Assertions.assertThat(artists.data.exists(id))
.as("object exists after insert").isTrue();
Assertions.assertThat(object)
.as("object exists after insert").get()
.as("object has correct properties").get()
.satisfies(obj -> {
Assertions.assertThat(obj.metadata().uuid())
.as("object id").isEqualTo(id);
Expand All @@ -60,8 +63,8 @@ public void testCreateGetDelete() throws IOException {
});

artists.data.delete(id);
object = artists.query.byId(id);
Assertions.assertThat(object).isEmpty().as("object not exists after deletion");
Assertions.assertThat(artists.data.exists(id))
.as("object not exists after deletion").isFalse();
}

@Test
Expand Down Expand Up @@ -175,4 +178,97 @@ public void testReferences_AddReplaceDelete() throws IOException {
.asInstanceOf(InstanceOfAssertFactories.list(WeaviateObject.class))
.isEmpty();
}

@Test
public void testReplace() throws IOException {
// Arrange
var nsBooks = ns("Books");

client.collections.create(nsBooks,
collection -> collection
.properties(Property.text("title"), Property.integer("year")));

// Add 1 book with 'title' only.
var books = client.collections.use(nsBooks);
var ivanhoe = books.data.insert(Map.of("title", "ivanhoe"));

// Act
books.data.replace(ivanhoe.metadata().uuid(),
replace -> replace.properties(Map.of("year", 1819)));

// Assert
var replacedIvanhoe = books.query.byId(ivanhoe.metadata().uuid());

Assertions.assertThat(replacedIvanhoe).get()
.as("has ONLY year property")
.extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP)
.doesNotContain(Map.entry("title", "ivanhoe"))
.contains(Map.entry("year", 1819L));
}

@Test
public void testUpdate() throws IOException {
// Arrange
var nsBooks = ns("Books");
var nsAuthors = ns("Authors");

client.collections.create(nsAuthors,
collection -> collection
.properties(Property.text("name")));

client.collections.create(nsBooks,
collection -> collection
.properties(Property.text("title"), Property.integer("year"))
.references(Property.reference("writtenBy", nsAuthors))
.vector(Hnsw.of(new NoneVectorizer())));

var authors = client.collections.use(nsAuthors);
var walter = authors.data.insert(Map.of("name", "walter scott"));

var vector = new Float[] { 1f, 2f, 3f };

var books = client.collections.use(nsBooks);

// Add 1 book without mentioning its author, year published,
// or supplying a vector.
var ivanhoe = books.data.insert(Map.of("title", "ivanhoe"));

// Act
books.data.update(ivanhoe.metadata().uuid(),
update -> update
.properties(Map.of("year", 1819))
.reference("writtenBy", Reference.objects(walter))
.vectors(Vectors.of(vector)));

// Assert
var updIvanhoe = books.query.byId(
ivanhoe.metadata().uuid(),
query -> query
.returnMetadata(Metadata.VECTOR)
.returnReferences(
QueryReference.single("writtenBy",
writtenBy -> writtenBy.returnMetadata(Metadata.ID))));

Assertions.assertThat(updIvanhoe).get()
.satisfies(book -> {
Assertions.assertThat(book)
.as("has both year and title property")
.extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP)
.contains(Map.entry("title", "ivanhoe"), Map.entry("year", 1819L));

Assertions.assertThat(book)
.as("has reference to Authors")
.extracting(WeaviateObject::references, InstanceOfAssertFactories.MAP)
.extractingByKey("writtenBy", InstanceOfAssertFactories.list(WeaviateObject.class))
.first()
.extracting(WeaviateObject::properties, InstanceOfAssertFactories.MAP)
.contains(Map.entry("name", "walter scott"));

Assertions.assertThat(book)
.as("has a vector")
.extracting(WeaviateObject::metadata)
.extracting(QueryMetadata::vectors)
.returns(vector, Vectors::getDefaultSingle);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public CollectionHandle(
CollectionDescriptor<T> collectionDescriptor) {

this.config = new WeaviateConfigClient(collectionDescriptor, restTransport, grpcTransport);
this.data = new WeaviateDataClient<>(collectionDescriptor, restTransport);
this.query = new WeaviateQueryClient<>(collectionDescriptor, grpcTransport);
this.data = new WeaviateDataClient<>(collectionDescriptor, restTransport, this.query);
this.aggregate = new WeaviateAggregateClient(collectionDescriptor, grpcTransport);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public CollectionHandleAsync(
CollectionDescriptor<T> collectionDescriptor) {

this.config = new WeaviateConfigClientAsync(collectionDescriptor, restTransport, grpcTransport);
this.data = new WeaviateDataClientAsync<>(collectionDescriptor, restTransport);
this.query = new WeaviateQueryClientAsync<>(collectionDescriptor, grpcTransport);
this.data = new WeaviateDataClientAsync<>(collectionDescriptor, restTransport, this.query);
this.aggregate = new WeaviateAggregateClientAsync(collectionDescriptor, grpcTransport);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.weaviate.client6.v1.api.collections.data;

import java.util.Collections;
import java.util.function.Function;

import com.google.gson.reflect.TypeToken;

import io.weaviate.client6.v1.api.collections.ObjectMetadata;
import io.weaviate.client6.v1.api.collections.Vectors;
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.internal.ObjectBuilder;
import io.weaviate.client6.v1.internal.json.JSON;
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
import io.weaviate.client6.v1.internal.rest.Endpoint;

public record ReplaceObjectRequest<T>(WeaviateObject<T, Reference, ObjectMetadata> object) {

static final <T> Endpoint<ReplaceObjectRequest<T>, Void> endpoint(CollectionDescriptor<T> collectionDescriptor) {
return Endpoint.of(
request -> "PUT",
request -> "/objects/" + collectionDescriptor.name() + "/" + request.object.metadata().uuid(),
(gson, request) -> JSON.serialize(request.object, TypeToken.getParameterized(
WeaviateObject.class, collectionDescriptor.typeToken().getType(), Reference.class, ObjectMetadata.class)),
request -> Collections.emptyMap(),
code -> code != 200,
(gson, response) -> null);
}

public static <T> ReplaceObjectRequest<T> of(String collectionName, String uuid,
Function<ReplaceObjectRequest.Builder<T>, ObjectBuilder<ReplaceObjectRequest<T>>> fn) {
return fn.apply(new Builder<>(collectionName, uuid)).build();
}

public ReplaceObjectRequest(Builder<T> builder) {
this(builder.object.build());
}

public static class Builder<T> implements ObjectBuilder<ReplaceObjectRequest<T>> {
private final WeaviateObject.Builder<T, Reference, ObjectMetadata> object = new WeaviateObject.Builder<>();
private final ObjectMetadata.Builder metadata = new ObjectMetadata.Builder();

public Builder(String collectionName, String uuid) {
this.object.collection(collectionName);
this.metadata.uuid(uuid);
}

public Builder<T> properties(T properties) {
this.object.properties(properties);
return this;
}

public Builder<T> vectors(Vectors vectors) {
this.metadata.vectors(vectors);
return this;
}

public Builder<T> reference(String property, Reference... references) {
this.object.reference(property, references);
return this;
}

@Override
public ReplaceObjectRequest<T> build() {
this.object.metadata(this.metadata.build());
return new ReplaceObjectRequest<>(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package io.weaviate.client6.v1.api.collections.data;

import java.util.Collections;
import java.util.function.Function;

import com.google.gson.reflect.TypeToken;

import io.weaviate.client6.v1.api.collections.ObjectMetadata;
import io.weaviate.client6.v1.api.collections.Vectors;
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.internal.ObjectBuilder;
import io.weaviate.client6.v1.internal.json.JSON;
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
import io.weaviate.client6.v1.internal.rest.Endpoint;

public record UpdateObjectRequest<T>(WeaviateObject<T, Reference, ObjectMetadata> object) {

static final <T> Endpoint<UpdateObjectRequest<T>, Void> endpoint(CollectionDescriptor<T> collectionDescriptor) {
return Endpoint.of(
request -> "PATCH",
request -> "/objects/" + collectionDescriptor.name() + "/" + request.object.metadata().uuid(),
(gson, request) -> JSON.serialize(request.object, TypeToken.getParameterized(
WeaviateObject.class, collectionDescriptor.typeToken().getType(), Reference.class, ObjectMetadata.class)),
request -> Collections.emptyMap(),
code -> code != 204,
(gson, response) -> null);
}

public static <T> UpdateObjectRequest<T> of(String collectionName, String uuid,
Function<UpdateObjectRequest.Builder<T>, ObjectBuilder<UpdateObjectRequest<T>>> fn) {
return fn.apply(new Builder<>(collectionName, uuid)).build();
}

public UpdateObjectRequest(Builder<T> builder) {
this(builder.object.build());
}

public static class Builder<T> implements ObjectBuilder<UpdateObjectRequest<T>> {
private final WeaviateObject.Builder<T, Reference, ObjectMetadata> object = new WeaviateObject.Builder<>();
private final ObjectMetadata.Builder metadata = new ObjectMetadata.Builder();

public Builder(String collectionName, String uuid) {
this.object.collection(collectionName);
this.metadata.uuid(uuid);
}

public Builder<T> properties(T properties) {
this.object.properties(properties);
return this;
}

public Builder<T> vectors(Vectors vectors) {
this.metadata.vectors(vectors);
return this;
}

public Builder<T> reference(String property, Reference... references) {
this.object.reference(property, references);
return this;
}

@Override
public UpdateObjectRequest<T> build() {
this.object.metadata(this.metadata.build());
return new UpdateObjectRequest<>(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import io.weaviate.client6.v1.api.collections.ObjectMetadata;
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClient;
import io.weaviate.client6.v1.internal.ObjectBuilder;
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
import io.weaviate.client6.v1.internal.rest.RestTransport;
Expand All @@ -13,9 +14,13 @@ public class WeaviateDataClient<T> {
private final RestTransport restTransport;
private final CollectionDescriptor<T> collectionDescriptor;

public WeaviateDataClient(CollectionDescriptor<T> collectionDescriptor, RestTransport restTransport) {
private final WeaviateQueryClient<T> query;

public WeaviateDataClient(CollectionDescriptor<T> collectionDescriptor, RestTransport restTransport,
WeaviateQueryClient<T> query) {
this.restTransport = restTransport;
this.collectionDescriptor = collectionDescriptor;
this.query = query;
}

public WeaviateObject<T, Object, ObjectMetadata> insert(T properties) throws IOException {
Expand All @@ -32,6 +37,22 @@ public WeaviateObject<T, Object, ObjectMetadata> insert(InsertObjectRequest<T> r
return this.restTransport.performRequest(request, InsertObjectRequest.endpoint(collectionDescriptor));
}

public boolean exists(String uuid) throws IOException {
return this.query.byId(uuid).isPresent();
}

public void update(String uuid, Function<UpdateObjectRequest.Builder<T>, ObjectBuilder<UpdateObjectRequest<T>>> fn)
throws IOException {
this.restTransport.performRequest(UpdateObjectRequest.of(collectionDescriptor.name(), uuid, fn),
UpdateObjectRequest.endpoint(collectionDescriptor));
}

public void replace(String uuid, Function<ReplaceObjectRequest.Builder<T>, ObjectBuilder<ReplaceObjectRequest<T>>> fn)
throws IOException {
this.restTransport.performRequest(ReplaceObjectRequest.of(collectionDescriptor.name(), uuid, fn),
ReplaceObjectRequest.endpoint(collectionDescriptor));
}

public void delete(String uuid) throws IOException {
this.restTransport.performRequest(new DeleteObjectRequest(collectionDescriptor.name(), uuid),
DeleteObjectRequest._ENDPOINT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import java.io.IOException;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

import io.weaviate.client6.v1.api.collections.ObjectMetadata;
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.api.collections.query.WeaviateQueryClientAsync;
import io.weaviate.client6.v1.internal.ObjectBuilder;
import io.weaviate.client6.v1.internal.orm.CollectionDescriptor;
import io.weaviate.client6.v1.internal.rest.RestTransport;
Expand All @@ -15,9 +17,13 @@ public class WeaviateDataClientAsync<T> {
private final RestTransport restTransport;
private final CollectionDescriptor<T> collectionDescriptor;

public WeaviateDataClientAsync(CollectionDescriptor<T> collectionDescriptor, RestTransport restTransport) {
private final WeaviateQueryClientAsync<T> query;

public WeaviateDataClientAsync(CollectionDescriptor<T> collectionDescriptor, RestTransport restTransport,
WeaviateQueryClientAsync<T> query) {
this.restTransport = restTransport;
this.collectionDescriptor = collectionDescriptor;
this.query = query;
}

public CompletableFuture<WeaviateObject<T, Object, ObjectMetadata>> insert(T properties) throws IOException {
Expand All @@ -35,6 +41,24 @@ public CompletableFuture<WeaviateObject<T, Object, ObjectMetadata>> insert(Inser
return this.restTransport.performRequestAsync(request, InsertObjectRequest.endpoint(collectionDescriptor));
}

public CompletableFuture<Boolean> exists(String uuid) {
return this.query.byId(uuid).thenApply(Optional::isPresent);
}

public CompletableFuture<Void> update(String uuid,
Function<UpdateObjectRequest.Builder<T>, ObjectBuilder<UpdateObjectRequest<T>>> fn)
throws IOException {
return this.restTransport.performRequestAsync(UpdateObjectRequest.of(collectionDescriptor.name(), uuid, fn),
UpdateObjectRequest.endpoint(collectionDescriptor));
}

public CompletableFuture<Void> replace(String uuid,
Function<ReplaceObjectRequest.Builder<T>, ObjectBuilder<ReplaceObjectRequest<T>>> fn)
throws IOException {
return this.restTransport.performRequestAsync(ReplaceObjectRequest.of(collectionDescriptor.name(), uuid, fn),
ReplaceObjectRequest.endpoint(collectionDescriptor));
}

public CompletableFuture<Void> delete(String uuid) {
return this.restTransport.performRequestAsync(new DeleteObjectRequest(collectionDescriptor.name(), uuid),
DeleteObjectRequest._ENDPOINT);
Expand Down