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
116 changes: 116 additions & 0 deletions src/it/java/io/weaviate/integration/DataITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
import io.weaviate.client6.v1.api.collections.Property;
import io.weaviate.client6.v1.api.collections.Vectors;
import io.weaviate.client6.v1.api.collections.WeaviateObject;
import io.weaviate.client6.v1.api.collections.data.BatchReference;
import io.weaviate.client6.v1.api.collections.data.DeleteManyResponse;
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.query.Where;
import io.weaviate.client6.v1.api.collections.vectorindex.Hnsw;
import io.weaviate.client6.v1.api.collections.vectorizers.NoneVectorizer;
import io.weaviate.containers.Container;
Expand Down Expand Up @@ -271,4 +274,117 @@ public void testUpdate() throws IOException {
.returns(vector, Vectors::getDefaultSingle);
});
}

@Test
public void testDeleteMany() throws IOException {
// Arrange
var nsThings = ns("Things");

client.collections.create(nsThings,
collection -> collection
.properties(Property.integer("last_used")));

var things = client.collections.use(nsThings);
things.data.insert(Map.of("last_used", 1));
var delete_1 = things.data.insert(Map.of("last_used", 5)).metadata().uuid();
var delete_2 = things.data.insert(Map.of("last_used", 9)).metadata().uuid();

// Act (dry run)
things.data.deleteMany(
Where.property("last_used").gte(4),
opt -> opt.dryRun(true));

// Assert
Assertions.assertThat(things.data.exists(delete_1)).as("#1 exists").isTrue();
Assertions.assertThat(things.data.exists(delete_2)).as("#2 exists").isTrue();

// Act (live run)
var deleted = things.data.deleteMany(
Where.property("last_used").gte(4),
opt -> opt.verbose(true));

// Assert
Assertions.assertThat(deleted)
.returns(2L, DeleteManyResponse::matches)
.returns(2L, DeleteManyResponse::successful)
.returns(0L, DeleteManyResponse::failed)
.extracting(DeleteManyResponse::objects, InstanceOfAssertFactories.list(DeleteManyResponse.DeletedObject.class))
.extracting(DeleteManyResponse.DeletedObject::uuid)
.containsOnly(delete_1, delete_2);

var count = things.aggregate.overAll(
cnt -> cnt
.objectLimit(100)
.includeTotalCount(true))
.totalCount();

Assertions.assertThat(count)
.as("one object remaining")
.isEqualTo(1);

}

@Test
public void testInsertMany() throws IOException {
// Arrange
var nsThings = ns("Things");

client.collections.create(nsThings);

var things = client.collections.use(nsThings);

// Act
things.data.insertMany(Map.of(), Map.of(), Map.of(), Map.of(), Map.of());

// Assert
var count = things.aggregate.overAll(
cnt -> cnt
.objectLimit(100)
.includeTotalCount(true))
.totalCount();

Assertions.assertThat(count)
.as("collection has 5 objects")
.isEqualTo(5);
}

@Test
public void testReferenceAddMany() throws IOException {
// Arrange
var nsCities = ns("Cities");
var nsAirports = ns("Airports");

client.collections.create(nsAirports);
client.collections.create(nsCities, c -> c
.references(Property.reference("hasAirports", nsAirports)));

var airports = client.collections.use(nsAirports);
var cities = client.collections.use(nsCities);

var alpha = airports.data.insert(Map.of()).uuid();
var goodburg = cities.data.insert(Map.of(), city -> city
.reference("hasAirports", Reference.uuids(alpha)));

// Act
var newAirports = airports.data.insertMany(Map.of(), Map.of());
var bravo = newAirports.responses().get(0).uuid();
var charlie = newAirports.responses().get(1).uuid();

var response = cities.data.referenceAddMany(BatchReference.uuids(goodburg, "hasAirports", bravo, charlie));

// Assert
Assertions.assertThat(response.errors()).isEmpty();

var goodburgAirports = cities.query.byId(goodburg.metadata().uuid(),
city -> city.returnReferences(
QueryReference.single("hasAirports",
airport -> airport.returnMetadata(Metadata.ID))));

Assertions.assertThat(goodburgAirports).get()
.as("Goodburg has 3 airports")
.extracting(WeaviateObject::references)
.extracting(references -> references.get("hasAirports"), InstanceOfAssertFactories.list(WeaviateObject.class))
.extracting(WeaviateObject::uuid)
.contains(alpha, bravo, charlie);
}
}
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, grpcTransport);
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, grpcTransport);
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
@@ -1,5 +1,6 @@
package io.weaviate.client6.v1.api.collections;

import java.util.UUID;
import java.util.function.Function;

import com.google.gson.annotations.SerializedName;
Expand All @@ -24,6 +25,10 @@ public static class Builder implements ObjectBuilder<ObjectMetadata> {
private String uuid;
private Vectors vectors;

public Builder uuid(UUID uuid) {
return uuid(uuid.toString());
}

public Builder uuid(String uuid) {
this.uuid = uuid;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ public Float[][] getDefaultMulti() {
return getMulti(VectorIndex.DEFAULT_VECTOR_NAME);
}

public Map<String, Object> asMap() {
return Map.copyOf(namedVectors);
}

public static enum CustomTypeAdapterFactory implements TypeAdapterFactory {
INSTANCE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
Expand All @@ -26,6 +27,21 @@ public record WeaviateObject<P, R, M extends WeaviateMetadata>(
Map<String, List<R>> references,
M metadata) {

/** Shorthand for accesing objects's UUID from metadata. */
public String uuid() {
return metadata.uuid();
}

/** Shorthand for accesing objects's vectors from metadata. */
public Vectors vectors() {
return metadata.vectors();
}

public static <P, R, M extends WeaviateMetadata> WeaviateObject<P, R, M> of(
Function<Builder<P, R, M>, ObjectBuilder<WeaviateObject<P, R, M>>> fn) {
return fn.apply(new Builder<>()).build();
}

public WeaviateObject(Builder<P, R, M> builder) {
this(builder.collection, builder.properties, builder.references, builder.metadata);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package io.weaviate.client6.v1.api.collections.data;

import java.io.IOException;
import java.util.Arrays;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import io.weaviate.client6.v1.api.collections.WeaviateObject;

public record BatchReference(String fromCollection, String fromProperty, String fromUuid, Reference reference) {

public static BatchReference[] objects(WeaviateObject<?, ?, ?> fromObject, String fromProperty,
WeaviateObject<?, ?, ?>... toObjects) {
return Arrays.stream(toObjects)
.map(to -> new BatchReference(
fromObject.collection(), fromProperty, fromObject.metadata().uuid(),
Reference.object(to)))
.toArray(BatchReference[]::new);
}

public static BatchReference[] uuids(WeaviateObject<?, ?, ?> fromObject, String fromProperty,
String... toUuids) {
return Arrays.stream(toUuids)
.map(to -> new BatchReference(
fromObject.collection(), fromProperty, fromObject.metadata().uuid(),
Reference.uuids(to)))
.toArray(BatchReference[]::new);
}

public static final TypeAdapter<BatchReference> TYPE_ADAPTER = new TypeAdapter<BatchReference>() {

@Override
public void write(JsonWriter out, BatchReference value) throws IOException {
out.beginObject();

out.name("from");
out.value(Reference.toBeacon(value.fromCollection, value.fromProperty, value.fromUuid));

out.name("to");
out.value(Reference.toBeacon(value.reference.collection(), value.reference.uuids().get(0)));

// TODO: add tenant

out.endObject();
}

@Override
public BatchReference read(JsonReader in) throws IOException {
String fromCollection = null;
String fromProperty = null;
String fromUuid = null;
Reference toReference = null;

in.beginObject();
while (in.hasNext()) {
switch (in.nextName()) {

case "from": {
var beacon = in.nextString();
beacon = beacon.replaceFirst("weaviate://localhost/", "");

var parts = beacon.split("/");
fromCollection = parts[0];
fromUuid = parts[1];
fromProperty = parts[2];
break;
}

case "to": {
String collection = null;
String id = null;

var beacon = in.nextString();
beacon = beacon.replaceFirst("weaviate://localhost/", "");
if (beacon.contains("/")) {
var parts = beacon.split("/");
collection = parts[0];
id = parts[1];
} else {
id = beacon;
}
toReference = new Reference(collection, id);
break;
}

// case "tenant":
// switch (in.peek()) {
// case STRING:
// in.nextString();
// case NULL:
// in.nextNull();
// default:
// // We don't expect anything else
// }
// System.out.println("processed tenant");
// break;
// default:
// in.skipValue();
}
}
in.endObject();

return new BatchReference(fromCollection, fromProperty, fromUuid, toReference);
}
}.nullSafe();
}
Loading