From e327fcea7dba6a035af4f6e52836b15c4092f647 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Mon, 8 Sep 2025 11:11:12 +0200 Subject: [PATCH 01/13] chore: use the same SLF4J version as surefire uses --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 32a819d49..8340230c2 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 3.27.4 1.0.4 5.19.0 - 2.0.17 + 1.7.36 1.5.18 5.14.0 2.19.2 From dd1c08e73c3f1159c5b48c78d4aed4f6707ca39b Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Mon, 8 Sep 2025 12:36:10 +0200 Subject: [PATCH 02/13] feat: create collection from Java POJO definition Supports text/int/number and corresponding array type properties. --- .../io/weaviate/integration/ORMITest.java | 109 ++++++++++++++++++ .../WeaviateCollectionsClient.java | 20 +++- .../v1/internal/orm/CollectionDescriptor.java | 20 +++- .../v1/internal/orm/PojoDescriptor.java | 108 +++++++++++++++++ 4 files changed, 248 insertions(+), 9 deletions(-) create mode 100644 src/it/java/io/weaviate/integration/ORMITest.java create mode 100644 src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java new file mode 100644 index 000000000..e0609018b --- /dev/null +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -0,0 +1,109 @@ +package io.weaviate.integration; + +import java.util.List; +import java.util.Map; + +import org.assertj.core.api.Assertions; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.Test; + +import io.weaviate.ConcurrentTest; +import io.weaviate.client6.v1.api.WeaviateClient; +import io.weaviate.client6.v1.api.collections.CollectionConfig; +import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.containers.Container; + +public class ORMITest extends ConcurrentTest { + private static WeaviateClient client = Container.WEAVIATE.getClient(); + + @Test + public void test_createCollection() throws Exception { + // Arrange + var things = client.collections.use(Things.class); + + // Act + client.collections.create(Things.class); + + // Assert + var config = things.config.get(); + Assertions.assertThat(config).get() + .returns("Things", CollectionConfig::collectionName) + .extracting(CollectionConfig::properties, InstanceOfAssertFactories.list(Property.class)) + .extracting(p -> Map.entry( + p.propertyName(), + p.dataTypes().get(0))) + .contains( + Map.entry("text", "text"), + Map.entry("textArray", "text[]"), + Map.entry("textList", "text[]"), + + Map.entry("short_", "int"), + Map.entry("shortBoxed", "int"), + Map.entry("shortArray", "int[]"), + Map.entry("shortBoxedArray", "int[]"), + Map.entry("shortBoxedList", "int[]"), + + Map.entry("int_", "int"), + Map.entry("intBoxed", "int"), + Map.entry("intArray", "int[]"), + Map.entry("intBoxedArray", "int[]"), + Map.entry("intBoxedList", "int[]"), + + Map.entry("long_", "int"), + Map.entry("longBoxed", "int"), + Map.entry("longArray", "int[]"), + Map.entry("longBoxedArray", "int[]"), + Map.entry("longBoxedList", "int[]"), + + Map.entry("float_", "number"), + Map.entry("floatBoxed", "number"), + Map.entry("floatArray", "number[]"), + Map.entry("floatBoxedArray", "number[]"), + Map.entry("floatBoxedList", "number[]"), + + Map.entry("double_", "number"), + Map.entry("doubleBoxed", "number"), + Map.entry("doubleArray", "number[]"), + Map.entry("doubleBoxedArray", "number[]"), + Map.entry("doubleBoxedList", "number[]")); + } +} + +class Things { + // text / text[] + private String text; + private String[] textArray; + private List textList; + + // int / int[] + private short short_; + private Short shortBoxed; + private short[] shortArray; + private Short[] shortBoxedArray; + private List shortBoxedList; + + private int int_; + private Integer intBoxed; + private int[] intArray; + private Integer[] intBoxedArray; + private List intBoxedList; + + private long long_; + private Long longBoxed; + private long[] longArray; + private Long[] longBoxedArray; + private List longBoxedList; + + // number / number[] + private float float_; + private Float floatBoxed; + private float[] floatArray; + private Float[] floatBoxedArray; + private List floatBoxedList; + + private double double_; + private Double doubleBoxed; + private double[] doubleArray; + private Double[] doubleBoxedArray; + private List doubleBoxedList; +} diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java index f71d7e9e9..04e5939d2 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java @@ -21,6 +21,10 @@ public WeaviateCollectionsClient(RestTransport restTransport, GrpcTransport grpc this.grpcTransport = grpcTransport; } + public CollectionHandle use(Class cls) { + return use(CollectionDescriptor.ofClass(cls), CollectionHandleDefaults.none()); + } + /** * Obtain a handle to send requests to a particular collection. * The returned object is thread-safe. @@ -42,11 +46,17 @@ public CollectionHandle> use(String collectionName) { public CollectionHandle> use( String collectionName, Function> fn) { - return new CollectionHandle<>( - restTransport, - grpcTransport, - CollectionDescriptor.ofMap(collectionName), - CollectionHandleDefaults.of(fn)); + return use(CollectionDescriptor.ofMap(collectionName), fn); + } + + private CollectionHandle use(CollectionDescriptor collection, + Function> fn) { + return new CollectionHandle<>(restTransport, grpcTransport, collection, CollectionHandleDefaults.of(fn)); + } + + public CollectionConfig create(Class cls) throws IOException { + var collection = CollectionDescriptor.ofClass(cls); + return create(CollectionConfig.of(collection.name(), collection.configFn())); } /** diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java index a122c7214..9302ce141 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java @@ -1,19 +1,31 @@ package io.weaviate.client6.v1.internal.orm; import java.util.Map; +import java.util.function.Function; import com.google.gson.reflect.TypeToken; -public sealed interface CollectionDescriptor permits MapDescriptor { +import io.weaviate.client6.v1.api.collections.CollectionConfig; +import io.weaviate.client6.v1.internal.ObjectBuilder; + +public sealed interface CollectionDescriptor permits MapDescriptor, PojoDescriptor { String name(); - TypeToken typeToken(); + TypeToken typeToken(); + + PropertiesReader propertiesReader(PropertiesT properties); - PropertiesReader propertiesReader(T properties); + PropertiesBuilder propertiesBuilder(); - PropertiesBuilder propertiesBuilder(); + default Function> configFn() { + return ObjectBuilder.identity(); + } static CollectionDescriptor> ofMap(String collectionName) { return new MapDescriptor(collectionName); } + + static CollectionDescriptor ofClass(Class cls) { + return new PojoDescriptor<>(cls); + } } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java new file mode 100644 index 000000000..23d5bbcbd --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -0,0 +1,108 @@ +package io.weaviate.client6.v1.internal.orm; + +import java.lang.reflect.ParameterizedType; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import com.google.gson.reflect.TypeToken; + +import io.weaviate.client6.v1.api.collections.CollectionConfig; +import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.client6.v1.internal.ObjectBuilder; + +final class PojoDescriptor implements CollectionDescriptor { + private static final Map, Function> ctors; + + static { + Map, Function> _ctors = new HashMap<>() { + { + } + }; + ctors = Collections.unmodifiableMap(_ctors); + } + + private final Class cls; + + PojoDescriptor(Class cls) { + this.cls = cls; + } + + @Override + public String name() { + return cls.getSimpleName(); + } + + @Override + public TypeToken typeToken() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'typeToken'"); + } + + @Override + public PropertiesReader propertiesReader(T properties) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'propertiesReader'"); + } + + @Override + public PropertiesBuilder propertiesBuilder() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'propertiesBuilder'"); + } + + @Override + public Function> configFn() { + return this::inspectClass; + } + + private ObjectBuilder inspectClass(CollectionConfig.Builder b) { + // Add properties; + for (var field : cls.getDeclaredFields()) { + var propertyName = field.getName(); + Function ctor; + var type = field.getType(); + if (type == String.class) { + ctor = Property::text; + } else if (type == String[].class) { + ctor = Property::textArray; + } else if (type == short.class || type == Short.class + || type == int.class || type == Integer.class + || type == long.class || type == Long.class) { + ctor = Property::integer; + } else if (type == short[].class || type == Short[].class + || type == int[].class || type == Integer[].class + || type == long[].class || type == Long[].class) { + ctor = Property::integerArray; + } else if (type == float.class || type == Float.class + || type == double.class || type == Double.class) { + ctor = Property::number; + } else if (type == float[].class || type == Float[].class + || type == double[].class || type == Double[].class) { + ctor = Property::numberArray; + } else if (type == List.class) { + var ptype = (ParameterizedType) field.getGenericType(); + var ltype = (Class) ptype.getActualTypeArguments()[0]; + if (ltype == String.class) { + ctor = Property::textArray; + } else if (ltype == short.class || ltype == Short.class + || ltype == int.class || ltype == Integer.class + || ltype == long.class || ltype == Long.class) { + ctor = Property::integerArray; + } else if (ltype == float.class || ltype == Float.class + || ltype == double.class || ltype == Double.class) { + ctor = Property::numberArray; + } else { + throw new IllegalArgumentException(ltype.getCanonicalName() + " is not supported"); + } + } else { + throw new IllegalArgumentException(type.getCanonicalName() + " is not supported"); + } + b.properties(ctor.apply(propertyName)); + } + return b; + } + +} From 4354a35bc09b5826764c4b37966631a1113f4ce4 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Mon, 8 Sep 2025 13:32:15 +0200 Subject: [PATCH 03/13] feat: extend supported data types - boolean/boolea[] - date/date[] - uuid/uuid[] Blob type currently not supported, as it's not exactly clear how best to distinguish it from normal String. --- .../io/weaviate/integration/ORMITest.java | 113 +++++++++++------- .../v1/internal/orm/PojoDescriptor.java | 91 ++++++++------ 2 files changed, 128 insertions(+), 76 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index e0609018b..1d962d882 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -1,7 +1,9 @@ package io.weaviate.integration; +import java.time.OffsetDateTime; import java.util.List; import java.util.Map; +import java.util.UUID; import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; @@ -16,6 +18,62 @@ public class ORMITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); + static class Things { + // text / text[] + private String text; + private String[] textArray; + private List textList; + + // date / date[] + private OffsetDateTime date; + private OffsetDateTime[] dateArray; + private List dateList; + + // uuid / uuid[] + private UUID uuid; + private UUID[] uuidArray; + private List uuidList; + + // int / int[] + private short short_; + private Short shortBoxed; + private short[] shortArray; + private Short[] shortBoxedArray; + private List shortBoxedList; + + private int int_; + private Integer intBoxed; + private int[] intArray; + private Integer[] intBoxedArray; + private List intBoxedList; + + private long long_; + private Long longBoxed; + private long[] longArray; + private Long[] longBoxedArray; + private List longBoxedList; + + // number / number[] + private float float_; + private Float floatBoxed; + private float[] floatArray; + private Float[] floatBoxedArray; + private List floatBoxedList; + + private double double_; + private Double doubleBoxed; + private double[] doubleArray; + private Double[] doubleBoxedArray; + private List doubleBoxedList; + + // boolean / boolean[] + private boolean boolean_; + private Boolean booleanBoxed; + private boolean[] booleanArray; + private Boolean[] booleanBoxedArray; + private List booleanBoxedList; + } + @Test public void test_createCollection() throws Exception { // Arrange @@ -37,6 +95,14 @@ public void test_createCollection() throws Exception { Map.entry("textArray", "text[]"), Map.entry("textList", "text[]"), + Map.entry("date", "date"), + Map.entry("dateArray", "date[]"), + Map.entry("dateList", "date[]"), + + Map.entry("uuid", "uuid"), + Map.entry("uuidArray", "uuid[]"), + Map.entry("uuidList", "uuid[]"), + Map.entry("short_", "int"), Map.entry("shortBoxed", "int"), Map.entry("shortArray", "int[]"), @@ -65,45 +131,12 @@ public void test_createCollection() throws Exception { Map.entry("doubleBoxed", "number"), Map.entry("doubleArray", "number[]"), Map.entry("doubleBoxedArray", "number[]"), - Map.entry("doubleBoxedList", "number[]")); - } -} + Map.entry("doubleBoxedList", "number[]"), -class Things { - // text / text[] - private String text; - private String[] textArray; - private List textList; - - // int / int[] - private short short_; - private Short shortBoxed; - private short[] shortArray; - private Short[] shortBoxedArray; - private List shortBoxedList; - - private int int_; - private Integer intBoxed; - private int[] intArray; - private Integer[] intBoxedArray; - private List intBoxedList; - - private long long_; - private Long longBoxed; - private long[] longArray; - private Long[] longBoxedArray; - private List longBoxedList; - - // number / number[] - private float float_; - private Float floatBoxed; - private float[] floatArray; - private Float[] floatBoxedArray; - private List floatBoxedList; - - private double double_; - private Double doubleBoxed; - private double[] doubleArray; - private Double[] doubleBoxedArray; - private List doubleBoxedList; + Map.entry("boolean_", "boolean"), + Map.entry("booleanBoxed", "boolean"), + Map.entry("booleanArray", "boolean[]"), + Map.entry("booleanBoxedArray", "boolean[]"), + Map.entry("booleanBoxedList", "boolean[]")); + } } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index 23d5bbcbd..63debc5da 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -1,10 +1,13 @@ package io.weaviate.client6.v1.internal.orm; +import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; +import java.time.OffsetDateTime; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.function.Function; import com.google.gson.reflect.TypeToken; @@ -14,14 +17,51 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; final class PojoDescriptor implements CollectionDescriptor { - private static final Map, Function> ctors; + private static final Map, Function> CTORS; static { - Map, Function> _ctors = new HashMap<>() { + Map, Function> ctors = new HashMap<>() { { + put(String.class, Property::text); + put(String[].class, Property::textArray); + + put(OffsetDateTime.class, Property::date); + put(OffsetDateTime[].class, Property::dateArray); + + put(UUID.class, Property::uuid); + put(UUID[].class, Property::uuidArray); + + put(boolean.class, Property::bool); + put(Boolean.class, Property::bool); + put(boolean[].class, Property::boolArray); + put(Boolean[].class, Property::boolArray); + + put(short.class, Property::integer); + put(Short.class, Property::integer); + put(int.class, Property::integer); + put(Integer.class, Property::integer); + put(long.class, Property::integer); + put(Long.class, Property::integer); + + put(short[].class, Property::integerArray); + put(Short[].class, Property::integerArray); + put(int[].class, Property::integerArray); + put(Integer[].class, Property::integerArray); + put(long[].class, Property::integerArray); + put(Long[].class, Property::integerArray); + + put(float.class, Property::number); + put(Float.class, Property::number); + put(double.class, Property::number); + put(Double.class, Property::number); + + put(float[].class, Property::numberArray); + put(Float[].class, Property::numberArray); + put(double[].class, Property::numberArray); + put(Double[].class, Property::numberArray); } }; - ctors = Collections.unmodifiableMap(_ctors); + CTORS = Collections.unmodifiableMap(ctors); } private final Class cls; @@ -64,42 +104,21 @@ private ObjectBuilder inspectClass(CollectionConfig.Builder b) var propertyName = field.getName(); Function ctor; var type = field.getType(); - if (type == String.class) { - ctor = Property::text; - } else if (type == String[].class) { - ctor = Property::textArray; - } else if (type == short.class || type == Short.class - || type == int.class || type == Integer.class - || type == long.class || type == Long.class) { - ctor = Property::integer; - } else if (type == short[].class || type == Short[].class - || type == int[].class || type == Integer[].class - || type == long[].class || type == Long[].class) { - ctor = Property::integerArray; - } else if (type == float.class || type == Float.class - || type == double.class || type == Double.class) { - ctor = Property::number; - } else if (type == float[].class || type == Float[].class - || type == double[].class || type == Double[].class) { - ctor = Property::numberArray; - } else if (type == List.class) { + + if (type == List.class) { var ptype = (ParameterizedType) field.getGenericType(); - var ltype = (Class) ptype.getActualTypeArguments()[0]; - if (ltype == String.class) { - ctor = Property::textArray; - } else if (ltype == short.class || ltype == Short.class - || ltype == int.class || ltype == Integer.class - || ltype == long.class || ltype == Long.class) { - ctor = Property::integerArray; - } else if (ltype == float.class || ltype == Float.class - || ltype == double.class || ltype == Double.class) { - ctor = Property::numberArray; - } else { - throw new IllegalArgumentException(ltype.getCanonicalName() + " is not supported"); - } + var argtype = (Class) ptype.getActualTypeArguments()[0]; + var arr = Array.newInstance(argtype, 0).getClass(); + ctor = CTORS.get(arr); } else { - throw new IllegalArgumentException(type.getCanonicalName() + " is not supported"); + ctor = CTORS.get(type); } + + if (ctor == null) { + throw new IllegalArgumentException(type.getCanonicalName() + " fields are not supported"); + } + + assert ctor != null; b.properties(ctor.apply(propertyName)); } return b; From 5d7878f7dea572e7a61b11bf2fabdc7de4eb7ae2 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Mon, 8 Sep 2025 13:51:15 +0200 Subject: [PATCH 04/13] feat: override class name with @Collection annotation --- src/it/java/io/weaviate/integration/ORMITest.java | 8 +++++--- .../v1/api/collections/annotations/Collection.java | 14 ++++++++++++++ .../client6/v1/internal/orm/PojoDescriptor.java | 5 +++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index 1d962d882..328b8169c 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -13,12 +13,14 @@ import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.collections.CollectionConfig; import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.containers.Container; public class ORMITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); - static class Things { + @Collection("Things") + static class Thing { // text / text[] private String text; private String[] textArray; @@ -77,10 +79,10 @@ static class Things { @Test public void test_createCollection() throws Exception { // Arrange - var things = client.collections.use(Things.class); + var things = client.collections.use(Thing.class); // Act - client.collections.create(Things.class); + client.collections.create(Thing.class); // Assert var config = things.config.get(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java new file mode 100644 index 000000000..9cb20d4a0 --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java @@ -0,0 +1,14 @@ +package io.weaviate.client6.v1.api.collections.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Collection { + String value(); + + String description() default ""; +} diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index 63debc5da..3b59efa62 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -14,6 +14,7 @@ import io.weaviate.client6.v1.api.collections.CollectionConfig; import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.client6.v1.internal.ObjectBuilder; final class PojoDescriptor implements CollectionDescriptor { @@ -72,6 +73,10 @@ final class PojoDescriptor implements CollectionDescriptor { @Override public String name() { + var annotation = cls.getAnnotation(Collection.class); + if (annotation != null) { + return annotation.value(); + } return cls.getSimpleName(); } From 726e898b4e64955c9579161cf31b025a5cb587f6 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Mon, 8 Sep 2025 19:24:17 +0200 Subject: [PATCH 05/13] feat: read/write data with POJOs internal.orm package now knows how to marshal and scan the response back into custom class instances. To simplify the implementation, we only support 'record' types for the moment, because they are final classes and do not have an 'extends' clause. Array[] and List() containers are supported, other container types not. --- .../io/weaviate/integration/ORMITest.java | 192 +++++++++++----- .../WeaviateCollectionsClient.java | 4 +- .../v1/internal/orm/CollectionDescriptor.java | 2 +- .../client6/v1/internal/orm/PojoBuilder.java | 215 ++++++++++++++++++ .../v1/internal/orm/PojoDescriptor.java | 11 +- .../client6/v1/internal/orm/PojoReader.java | 27 +++ 6 files changed, 385 insertions(+), 66 deletions(-) create mode 100644 src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java create mode 100644 src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index 328b8169c..57a38ddfd 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -7,12 +7,14 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.BeforeClass; import org.junit.Test; import io.weaviate.ConcurrentTest; import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.collections.CollectionConfig; import io.weaviate.client6.v1.api.collections.Property; +import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.containers.Container; @@ -20,60 +22,65 @@ public class ORMITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); @Collection("Things") - static class Thing { - // text / text[] - private String text; - private String[] textArray; - private List textList; - - // date / date[] - private OffsetDateTime date; - private OffsetDateTime[] dateArray; - private List dateList; - - // uuid / uuid[] - private UUID uuid; - private UUID[] uuidArray; - private List uuidList; - - // int / int[] - private short short_; - private Short shortBoxed; - private short[] shortArray; - private Short[] shortBoxedArray; - private List shortBoxedList; - - private int int_; - private Integer intBoxed; - private int[] intArray; - private Integer[] intBoxedArray; - private List intBoxedList; - - private long long_; - private Long longBoxed; - private long[] longArray; - private Long[] longBoxedArray; - private List longBoxedList; - - // number / number[] - private float float_; - private Float floatBoxed; - private float[] floatArray; - private Float[] floatBoxedArray; - private List floatBoxedList; - - private double double_; - private Double doubleBoxed; - private double[] doubleArray; - private Double[] doubleBoxedArray; - private List doubleBoxedList; - - // boolean / boolean[] - private boolean boolean_; - private Boolean booleanBoxed; - private boolean[] booleanArray; - private Boolean[] booleanBoxedArray; - private List booleanBoxedList; + static record Thing( + // text / text[] + String text, + String[] textArray, + List textList, + + // date / date[] + OffsetDateTime date, + OffsetDateTime[] dateArray, + List dateList, + + // uuid / uuid[] + UUID uuid, + UUID[] uuidArray, + List uuidList, + + // int / int[] + short short_, + Short shortBoxed, + short[] shortArray, + Short[] shortBoxedArray, + List shortBoxedList, + + int int_, + Integer intBoxed, + int[] intArray, + Integer[] intBoxedArray, + List intBoxedList, + + long long_, + Long longBoxed, + long[] longArray, + Long[] longBoxedArray, + List longBoxedList, + + // number / number[] + float float_, + Float floatBoxed, + float[] floatArray, + Float[] floatBoxedArray, + List floatBoxedList, + + double double_, + Double doubleBoxed, + double[] doubleArray, + Double[] doubleBoxedArray, + List doubleBoxedList, + + // boolean / boolean[] + boolean boolean_, + Boolean booleanBoxed, + boolean[] booleanArray, + Boolean[] booleanBoxedArray, + List booleanBoxedList) { + } + + @BeforeClass + public static void setUp() throws Exception { + client.collections.create(Thing.class); } @Test @@ -82,10 +89,9 @@ public void test_createCollection() throws Exception { var things = client.collections.use(Thing.class); // Act - client.collections.create(Thing.class); + var config = things.config.get(); // Assert - var config = things.config.get(); Assertions.assertThat(config).get() .returns("Things", CollectionConfig::collectionName) .extracting(CollectionConfig::properties, InstanceOfAssertFactories.list(Property.class)) @@ -141,4 +147,78 @@ public void test_createCollection() throws Exception { Map.entry("booleanBoxedArray", "boolean[]"), Map.entry("booleanBoxedList", "boolean[]")); } + + @Test + public void test_insertAndQuery() throws Exception { + short short_ = 666; + int int_ = 666; + long long_ = 666L; + float float_ = 666f; + double double_ = 666d; + boolean boolean_ = true; + UUID uuid = UUID.randomUUID(); + OffsetDateTime date = OffsetDateTime.now(); + String text = "hello"; + + var thing = new Thing( + text, + new String[] { text }, + List.of(text), + + OffsetDateTime.now(), + new OffsetDateTime[] { date }, + List.of(date), + + UUID.randomUUID(), + new UUID[] { uuid }, + List.of(uuid), + + short_, + short_, + new short[] { short_ }, + new Short[] { short_ }, + List.of(short_), + + int_, + int_, + new int[] { int_ }, + new Integer[] { int_ }, + List.of(int_), + + long_, + long_, + new long[] { long_ }, + new Long[] { long_ }, + List.of(long_), + + float_, + float_, + new float[] { float_ }, + new Float[] { float_ }, + List.of(float_), + + double_, + double_, + new double[] { double_ }, + new Double[] { double_ }, + List.of(double_), + + boolean_, + boolean_, + new boolean[] { boolean_ }, + new Boolean[] { boolean_ }, + List.of(boolean_)); + + var things = client.collections.use(Thing.class); + + // Act + var inserted = things.data.insert(thing); + + // Assert + var got = things.query.byId(inserted.uuid()); + Assertions.assertThat(got).get() + .extracting(WeaviateObject::properties, InstanceOfAssertFactories.type(Thing.class)); + + // TODO: add assertions; + } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java index 04e5939d2..088bd2403 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java @@ -21,7 +21,7 @@ public WeaviateCollectionsClient(RestTransport restTransport, GrpcTransport grpc this.grpcTransport = grpcTransport; } - public CollectionHandle use(Class cls) { + public CollectionHandle use(Class cls) { return use(CollectionDescriptor.ofClass(cls), CollectionHandleDefaults.none()); } @@ -54,7 +54,7 @@ private CollectionHandle use(CollectionDescriptor(restTransport, grpcTransport, collection, CollectionHandleDefaults.of(fn)); } - public CollectionConfig create(Class cls) throws IOException { + public CollectionConfig create(Class cls) throws IOException { var collection = CollectionDescriptor.ofClass(cls); return create(CollectionConfig.of(collection.name(), collection.configFn())); } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java index 9302ce141..c202ab9f9 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java @@ -25,7 +25,7 @@ static CollectionDescriptor> ofMap(String collectionName) { return new MapDescriptor(collectionName); } - static CollectionDescriptor ofClass(Class cls) { + static CollectionDescriptor ofClass(Class cls) { return new PojoDescriptor<>(cls); } } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java new file mode 100644 index 000000000..02cced586 --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java @@ -0,0 +1,215 @@ +package io.weaviate.client6.v1.internal.orm; + +import java.lang.reflect.Constructor; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.ArrayUtils; + +final class PojoBuilder implements PropertiesBuilder { + private final Constructor ctor; + private final Map ctorArgs; + + static record Arg(Class type, Object value) { + Arg withValue(Object value) { + return new Arg(this.type, value); + } + } + + PojoBuilder(Class cls) { + var args = cls.getRecordComponents(); + ctorArgs = new LinkedHashMap(args.length); + + var componentTypes = Arrays.stream(args) + .map(arg -> { + // LinkedHahsMap allows null values. + var type = arg.getType(); + ctorArgs.put(arg.getName(), new Arg(type, null)); + return type; + }) + .toArray(Class[]::new); + try { + ctor = cls.getDeclaredConstructor(componentTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private void setValue(String fieldName, Object value) { + if (!ctorArgs.containsKey(fieldName)) { + return; + } + var arg = ctorArgs.get(fieldName); + // value = coerse.apply(value); + ctorArgs.put(fieldName, arg.withValue(value)); + } + + private Class getArgType(String fieldName) { + return ctorArgs.get(fieldName).type(); + } + + private boolean isArray(String fieldName, Class... classes) { + var type = getArgType(fieldName); + if (!type.isArray()) { + return false; + } + if (classes.length == 0) { + return true; + } + var componentType = type.getComponentType(); + for (final var cls : classes) { + if (componentType == cls) { + return true; + } + } + return false; + } + + /** Is either of types. */ + private boolean isType(String fieldName, Class... classes) { + var type = getArgType(fieldName); + for (final var cls : classes) { + if (type == cls) { + return true; + } + } + return false; + } + + @Override + public void setNull(String property) { + setValue(property, null); + } + + @Override + public void setText(String property, String value) { + setValue(property, value); + } + + @Override + public void setBoolean(String property, Boolean value) { + if (isType(property, boolean.class)) { + setValue(property, value.booleanValue()); + } else { + setValue(property, value); + } + } + + @Override + // TODO: rename to setLong + public void setInteger(String property, Long value) { + if (isType(property, short.class, Short.class)) { + setValue(property, value.shortValue()); + } else if (isType(property, int.class, Integer.class)) { + setValue(property, value.intValue()); + } else { + setValue(property, value); + } + } + + @Override + public void setDouble(String property, Double value) { + if (isType(property, float.class, Float.class)) { + setValue(property, value.floatValue()); + } else { + setValue(property, value); + } + } + + @Override + public void setBlob(String property, String value) { + setValue(property, value); + } + + @Override + public void setOffsetDateTime(String property, OffsetDateTime value) { + setValue(property, value); + } + + @Override + public void setUuid(String property, UUID value) { + setValue(property, value); + } + + @Override + public void setTextArray(String property, List value) { + setValue(property, isArray(property) + ? value.toArray(String[]::new) + : value); + + } + + @Override + public void setLongArray(String property, List value) { + if (isArray(property, short.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::shortValue).toArray(Short[]::new))); + } else if (isArray(property, Short.class)) { + setValue(property, value.stream().map(Long::shortValue).toArray(Short[]::new)); + } else if (isArray(property, int.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::intValue).toArray(Integer[]::new))); + } else if (isArray(property, Integer.class)) { + setValue(property, value.stream().map(Long::intValue).toArray(Integer[]::new)); + } else if (isArray(property, long.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::longValue).toArray(Long[]::new))); + } else if (isArray(property, Long.class)) { + setValue(property, value.stream().toArray(Long[]::new)); + } else { + setValue(property, value); + } + } + + @Override + public void setDoubleArray(String property, List value) { + if (isArray(property, float.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Double::floatValue).toArray(Float[]::new))); + } else if (isArray(property, Float.class)) { + setValue(property, value.stream().map(Double::floatValue).toArray(Float[]::new)); + } else if (isArray(property, double.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Double::doubleValue).toArray(Double[]::new))); + } else if (isArray(property, Double.class)) { + setValue(property, value.stream().toArray(Double[]::new)); + } else { + setValue(property, value); + } + } + + @Override + public void setUuidArray(String property, List value) { + setValue(property, isArray(property) + ? value.toArray(UUID[]::new) + : value); + } + + @Override + public void setBooleanArray(String property, List value) { + if (isArray(property, boolean.class)) { + setValue(property, ArrayUtils.toPrimitive(value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new))); + } else if (isArray(property, Boolean.class)) { + setValue(property, value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new)); + } else { + setValue(property, value); + } + } + + @Override + public void setOffsetDateTimeArray(String property, List value) { + setValue(property, isArray(property) + ? value.toArray(OffsetDateTime[]::new) + : value); + } + + @Override + public PropertiesT build() { + Object[] args = ctorArgs.values().stream().map(Arg::value).toArray(); + try { + ctor.setAccessible(true); + return ctor.newInstance(args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index 3b59efa62..583f32407 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -17,7 +17,7 @@ import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.client6.v1.internal.ObjectBuilder; -final class PojoDescriptor implements CollectionDescriptor { +final class PojoDescriptor implements CollectionDescriptor { private static final Map, Function> CTORS; static { @@ -82,20 +82,17 @@ public String name() { @Override public TypeToken typeToken() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'typeToken'"); + return TypeToken.get(cls); } @Override public PropertiesReader propertiesReader(T properties) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'propertiesReader'"); + return new PojoReader<>(properties); } @Override public PropertiesBuilder propertiesBuilder() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'propertiesBuilder'"); + return new PojoBuilder<>(cls); } @Override diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java new file mode 100644 index 000000000..da3ceb75f --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java @@ -0,0 +1,27 @@ +package io.weaviate.client6.v1.internal.orm; + +import java.util.HashMap; +import java.util.Map; + +final class PojoReader implements PropertiesReader { + private final PropertiesT properties; + + PojoReader(PropertiesT properties) { + this.properties = properties; + } + + @Override + public Map readProperties() { + var out = new HashMap(); + for (var field : properties.getClass().getDeclaredFields()) { + var propertyName = field.getName(); + field.setAccessible(true); + try { + out.put(propertyName, field.get(properties)); + } catch (IllegalAccessException e) { + assert e == null : e.getMessage(); + } + } + return out; + } +} From 69476d6e17b16867d09a005f009f64441450bae3 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 10 Sep 2025 16:59:04 +0200 Subject: [PATCH 06/13] feat: add @Property annotation to decouple class field names from property names --- .../java/io/weaviate/containers/Weaviate.java | 8 +- .../io/weaviate/integration/ORMITest.java | 35 +++-- .../api/collections/annotations/Property.java | 12 ++ .../client6/v1/internal/json/JSON.java | 5 + .../client6/v1/internal/orm/PojoBuilder.java | 147 +++++++++--------- .../v1/internal/orm/PojoDescriptor.java | 29 +++- .../orm/PropertyFieldNamingStrategy.java | 14 ++ 7 files changed, 158 insertions(+), 92 deletions(-) create mode 100644 src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java create mode 100644 src/main/java/io/weaviate/client6/v1/internal/orm/PropertyFieldNamingStrategy.java diff --git a/src/it/java/io/weaviate/containers/Weaviate.java b/src/it/java/io/weaviate/containers/Weaviate.java index e1bb7157f..8b373e98b 100644 --- a/src/it/java/io/weaviate/containers/Weaviate.java +++ b/src/it/java/io/weaviate/containers/Weaviate.java @@ -92,13 +92,12 @@ public static Weaviate.Builder custom() { public static class Builder { private String versionTag; private Set enableModules = new HashSet<>(); - private boolean telemetry; private Map environment = new HashMap<>(); public Builder() { this.versionTag = VERSION; - this.telemetry = false; + enableAutoSchema(false); } public Builder withVersion(String version) { @@ -143,6 +142,11 @@ public Builder enableTelemetry(boolean enable) { return this; } + public Builder enableAutoSchema(boolean enable) { + environment.put("AUTOSCHEMA_ENABLED", Boolean.toString(!enable)); + return this; + } + public Builder enableAnonymousAccess(boolean enable) { environment.put("AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED", Boolean.toString(enable)); return this; diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index 57a38ddfd..da9d116be 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -13,15 +13,15 @@ import io.weaviate.ConcurrentTest; import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.collections.CollectionConfig; -import io.weaviate.client6.v1.api.collections.Property; import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.annotations.Collection; +import io.weaviate.client6.v1.api.collections.annotations.Property; import io.weaviate.containers.Container; public class ORMITest extends ConcurrentTest { private static WeaviateClient client = Container.WEAVIATE.getClient(); - @Collection("Things") + @Collection("ORMITest") static record Thing( // text / text[] String text, @@ -39,39 +39,39 @@ static record Thing( List uuidList, // int / int[] - short short_, + @Property("short") short short_, Short shortBoxed, short[] shortArray, Short[] shortBoxedArray, List shortBoxedList, - int int_, + @Property("int") int int_, Integer intBoxed, int[] intArray, Integer[] intBoxedArray, List intBoxedList, - long long_, + @Property("long") long long_, Long longBoxed, long[] longArray, Long[] longBoxedArray, List longBoxedList, // number / number[] - float float_, + @Property("float") float float_, Float floatBoxed, float[] floatArray, Float[] floatBoxedArray, List floatBoxedList, - double double_, + @Property("double") double double_, Double doubleBoxed, double[] doubleArray, Double[] doubleBoxedArray, List doubleBoxedList, // boolean / boolean[] - boolean boolean_, + @Property("boolean") boolean boolean_, Boolean booleanBoxed, boolean[] booleanArray, Boolean[] booleanBoxedArray, @@ -93,8 +93,9 @@ public void test_createCollection() throws Exception { // Assert Assertions.assertThat(config).get() - .returns("Things", CollectionConfig::collectionName) - .extracting(CollectionConfig::properties, InstanceOfAssertFactories.list(Property.class)) + .returns("ORMITest", CollectionConfig::collectionName) + .extracting(CollectionConfig::properties, + InstanceOfAssertFactories.list(io.weaviate.client6.v1.api.collections.Property.class)) .extracting(p -> Map.entry( p.propertyName(), p.dataTypes().get(0))) @@ -111,37 +112,37 @@ public void test_createCollection() throws Exception { Map.entry("uuidArray", "uuid[]"), Map.entry("uuidList", "uuid[]"), - Map.entry("short_", "int"), + Map.entry("short", "int"), Map.entry("shortBoxed", "int"), Map.entry("shortArray", "int[]"), Map.entry("shortBoxedArray", "int[]"), Map.entry("shortBoxedList", "int[]"), - Map.entry("int_", "int"), + Map.entry("int", "int"), Map.entry("intBoxed", "int"), Map.entry("intArray", "int[]"), Map.entry("intBoxedArray", "int[]"), Map.entry("intBoxedList", "int[]"), - Map.entry("long_", "int"), + Map.entry("long", "int"), Map.entry("longBoxed", "int"), Map.entry("longArray", "int[]"), Map.entry("longBoxedArray", "int[]"), Map.entry("longBoxedList", "int[]"), - Map.entry("float_", "number"), + Map.entry("float", "number"), Map.entry("floatBoxed", "number"), Map.entry("floatArray", "number[]"), Map.entry("floatBoxedArray", "number[]"), Map.entry("floatBoxedList", "number[]"), - Map.entry("double_", "number"), + Map.entry("double", "number"), Map.entry("doubleBoxed", "number"), Map.entry("doubleArray", "number[]"), Map.entry("doubleBoxedArray", "number[]"), Map.entry("doubleBoxedList", "number[]"), - Map.entry("boolean_", "boolean"), + Map.entry("boolean", "boolean"), Map.entry("booleanBoxed", "boolean"), Map.entry("booleanArray", "boolean[]"), Map.entry("booleanBoxedArray", "boolean[]"), @@ -221,4 +222,6 @@ public void test_insertAndQuery() throws Exception { // TODO: add assertions; } + + // TODO: insertMany (batch) } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java new file mode 100644 index 000000000..9dbd6118f --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java @@ -0,0 +1,12 @@ +package io.weaviate.client6.v1.api.collections.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Property { + String value(); +} diff --git a/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java b/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java index a56fce609..7a157b2b9 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java +++ b/src/main/java/io/weaviate/client6/v1/internal/json/JSON.java @@ -4,6 +4,8 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import io.weaviate.client6.v1.internal.orm.PropertyFieldNamingStrategy; + public final class JSON { private static final Gson gson; @@ -42,6 +44,9 @@ public final class JSON { gsonBuilder.registerTypeAdapter( io.weaviate.client6.v1.api.collections.data.ReferenceAddManyResponse.class, io.weaviate.client6.v1.api.collections.data.ReferenceAddManyResponse.CustomJsonDeserializer.INSTANCE); + + // ORM FieldNaminsStrategy ------------------------------------------------ + gsonBuilder.setFieldNamingStrategy(PropertyFieldNamingStrategy.INSTANCE); gson = gsonBuilder.create(); } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java index 02cced586..1fa65750c 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoBuilder.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.ArrayUtils; final class PojoBuilder implements PropertiesBuilder { + private final PojoDescriptor descriptor; private final Constructor ctor; private final Map ctorArgs; @@ -20,40 +21,42 @@ Arg withValue(Object value) { } } - PojoBuilder(Class cls) { - var args = cls.getRecordComponents(); + PojoBuilder(PojoDescriptor descriptor) { + this.descriptor = descriptor; + + var args = descriptor._class().getRecordComponents(); ctorArgs = new LinkedHashMap(args.length); var componentTypes = Arrays.stream(args) .map(arg -> { - // LinkedHahsMap allows null values. + // LinkedHashMap allows null values. var type = arg.getType(); ctorArgs.put(arg.getName(), new Arg(type, null)); return type; }) .toArray(Class[]::new); try { - ctor = cls.getDeclaredConstructor(componentTypes); + ctor = descriptor._class().getDeclaredConstructor(componentTypes); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException(e); } } - private void setValue(String fieldName, Object value) { + private void setValue(String propertyName, Object value) { + var fieldName = descriptor.fieldName(propertyName); if (!ctorArgs.containsKey(fieldName)) { return; } var arg = ctorArgs.get(fieldName); - // value = coerse.apply(value); ctorArgs.put(fieldName, arg.withValue(value)); } - private Class getArgType(String fieldName) { - return ctorArgs.get(fieldName).type(); + private Class getArgType(String propertyName) { + return ctorArgs.get(descriptor.fieldName(propertyName)).type(); } - private boolean isArray(String fieldName, Class... classes) { - var type = getArgType(fieldName); + private boolean isArray(String propertyName, Class... classes) { + var type = getArgType(propertyName); if (!type.isArray()) { return false; } @@ -70,8 +73,8 @@ private boolean isArray(String fieldName, Class... classes) { } /** Is either of types. */ - private boolean isType(String fieldName, Class... classes) { - var type = getArgType(fieldName); + private boolean isType(String propertyName, Class... classes) { + var type = getArgType(propertyName); for (final var cls : classes) { if (type == cls) { return true; @@ -81,123 +84,123 @@ private boolean isType(String fieldName, Class... classes) { } @Override - public void setNull(String property) { - setValue(property, null); + public void setNull(String propertyName) { + setValue(propertyName, null); } @Override - public void setText(String property, String value) { - setValue(property, value); + public void setText(String propertyName, String value) { + setValue(propertyName, value); } @Override - public void setBoolean(String property, Boolean value) { - if (isType(property, boolean.class)) { - setValue(property, value.booleanValue()); + public void setBoolean(String propertyName, Boolean value) { + if (isType(propertyName, boolean.class)) { + setValue(propertyName, value.booleanValue()); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override // TODO: rename to setLong - public void setInteger(String property, Long value) { - if (isType(property, short.class, Short.class)) { - setValue(property, value.shortValue()); - } else if (isType(property, int.class, Integer.class)) { - setValue(property, value.intValue()); + public void setInteger(String propertyName, Long value) { + if (isType(propertyName, short.class, Short.class)) { + setValue(propertyName, value.shortValue()); + } else if (isType(propertyName, int.class, Integer.class)) { + setValue(propertyName, value.intValue()); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override - public void setDouble(String property, Double value) { - if (isType(property, float.class, Float.class)) { - setValue(property, value.floatValue()); + public void setDouble(String propertyName, Double value) { + if (isType(propertyName, float.class, Float.class)) { + setValue(propertyName, value.floatValue()); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override - public void setBlob(String property, String value) { - setValue(property, value); + public void setBlob(String propertyName, String value) { + setValue(propertyName, value); } @Override - public void setOffsetDateTime(String property, OffsetDateTime value) { - setValue(property, value); + public void setOffsetDateTime(String propertyName, OffsetDateTime value) { + setValue(propertyName, value); } @Override - public void setUuid(String property, UUID value) { - setValue(property, value); + public void setUuid(String propertyName, UUID value) { + setValue(propertyName, value); } @Override - public void setTextArray(String property, List value) { - setValue(property, isArray(property) + public void setTextArray(String propertyName, List value) { + setValue(propertyName, isArray(propertyName) ? value.toArray(String[]::new) : value); } @Override - public void setLongArray(String property, List value) { - if (isArray(property, short.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::shortValue).toArray(Short[]::new))); - } else if (isArray(property, Short.class)) { - setValue(property, value.stream().map(Long::shortValue).toArray(Short[]::new)); - } else if (isArray(property, int.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::intValue).toArray(Integer[]::new))); - } else if (isArray(property, Integer.class)) { - setValue(property, value.stream().map(Long::intValue).toArray(Integer[]::new)); - } else if (isArray(property, long.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Long::longValue).toArray(Long[]::new))); - } else if (isArray(property, Long.class)) { - setValue(property, value.stream().toArray(Long[]::new)); + public void setLongArray(String propertyName, List value) { + if (isArray(propertyName, short.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Long::shortValue).toArray(Short[]::new))); + } else if (isArray(propertyName, Short.class)) { + setValue(propertyName, value.stream().map(Long::shortValue).toArray(Short[]::new)); + } else if (isArray(propertyName, int.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Long::intValue).toArray(Integer[]::new))); + } else if (isArray(propertyName, Integer.class)) { + setValue(propertyName, value.stream().map(Long::intValue).toArray(Integer[]::new)); + } else if (isArray(propertyName, long.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Long::longValue).toArray(Long[]::new))); + } else if (isArray(propertyName, Long.class)) { + setValue(propertyName, value.stream().toArray(Long[]::new)); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override - public void setDoubleArray(String property, List value) { - if (isArray(property, float.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Double::floatValue).toArray(Float[]::new))); - } else if (isArray(property, Float.class)) { - setValue(property, value.stream().map(Double::floatValue).toArray(Float[]::new)); - } else if (isArray(property, double.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Double::doubleValue).toArray(Double[]::new))); - } else if (isArray(property, Double.class)) { - setValue(property, value.stream().toArray(Double[]::new)); + public void setDoubleArray(String propertyName, List value) { + if (isArray(propertyName, float.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Double::floatValue).toArray(Float[]::new))); + } else if (isArray(propertyName, Float.class)) { + setValue(propertyName, value.stream().map(Double::floatValue).toArray(Float[]::new)); + } else if (isArray(propertyName, double.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Double::doubleValue).toArray(Double[]::new))); + } else if (isArray(propertyName, Double.class)) { + setValue(propertyName, value.stream().toArray(Double[]::new)); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override - public void setUuidArray(String property, List value) { - setValue(property, isArray(property) + public void setUuidArray(String propertyName, List value) { + setValue(propertyName, isArray(propertyName) ? value.toArray(UUID[]::new) : value); } @Override - public void setBooleanArray(String property, List value) { - if (isArray(property, boolean.class)) { - setValue(property, ArrayUtils.toPrimitive(value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new))); - } else if (isArray(property, Boolean.class)) { - setValue(property, value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new)); + public void setBooleanArray(String propertyName, List value) { + if (isArray(propertyName, boolean.class)) { + setValue(propertyName, ArrayUtils.toPrimitive(value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new))); + } else if (isArray(propertyName, Boolean.class)) { + setValue(propertyName, value.stream().map(Boolean::booleanValue).toArray(Boolean[]::new)); } else { - setValue(property, value); + setValue(propertyName, value); } } @Override - public void setOffsetDateTimeArray(String property, List value) { - setValue(property, isArray(property) + public void setOffsetDateTimeArray(String propertyName, List value) { + setValue(propertyName, isArray(propertyName) ? value.toArray(OffsetDateTime[]::new) : value); } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index 583f32407..ee9b01112 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -1,14 +1,17 @@ package io.weaviate.client6.v1.internal.orm; import java.lang.reflect.Array; +import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.time.OffsetDateTime; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Function; +import java.util.stream.Collectors; import com.google.gson.reflect.TypeToken; @@ -66,9 +69,31 @@ final class PojoDescriptor implements CollectionDescriptor } private final Class cls; + private final Map propertyToField; PojoDescriptor(Class cls) { this.cls = cls; + this.propertyToField = Arrays.stream(cls.getDeclaredFields()) + .collect(Collectors.toUnmodifiableMap(PojoDescriptor::propertyName, Field::getName)); + } + + Class _class() { + return cls; + } + + /** Get collection property name for a class field. */ + static String propertyName(Field field) { + var annotation = field.getAnnotation(io.weaviate.client6.v1.api.collections.annotations.Property.class); + var propertyName = field.getName(); + if (annotation != null) { + propertyName = annotation.value(); + } + return propertyName; + } + + /** Get class field name for a collection property. */ + String fieldName(String propertyName) { + return propertyToField.getOrDefault(propertyName, propertyName); } @Override @@ -92,7 +117,7 @@ public PropertiesReader propertiesReader(T properties) { @Override public PropertiesBuilder propertiesBuilder() { - return new PojoBuilder<>(cls); + return new PojoBuilder<>(this); } @Override @@ -103,7 +128,7 @@ public Function> confi private ObjectBuilder inspectClass(CollectionConfig.Builder b) { // Add properties; for (var field : cls.getDeclaredFields()) { - var propertyName = field.getName(); + var propertyName = propertyName(field); Function ctor; var type = field.getType(); diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PropertyFieldNamingStrategy.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PropertyFieldNamingStrategy.java new file mode 100644 index 000000000..0d6bdd80e --- /dev/null +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PropertyFieldNamingStrategy.java @@ -0,0 +1,14 @@ +package io.weaviate.client6.v1.internal.orm; + +import java.lang.reflect.Field; + +import com.google.gson.FieldNamingStrategy; + +public enum PropertyFieldNamingStrategy implements FieldNamingStrategy { + INSTANCE; + + @Override + public String translateName(Field field) { + return PojoDescriptor.propertyName(field); + } +} From e5881c3629bbc949763c9e267dcaad012f4cf428 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 10 Sep 2025 17:46:01 +0200 Subject: [PATCH 07/13] test: add more assertions --- .../io/weaviate/integration/ORMITest.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index da9d116be..52cfa436c 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -7,6 +7,7 @@ import org.assertj.core.api.Assertions; import org.assertj.core.api.InstanceOfAssertFactories; +import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration; import org.junit.BeforeClass; import org.junit.Test; @@ -149,13 +150,20 @@ public void test_createCollection() throws Exception { Map.entry("booleanBoxedList", "boolean[]")); } + private final RecursiveComparisonConfiguration COMPARISON_CONFIG = RecursiveComparisonConfiguration.builder() + // Assertj is having a really bad time comparing List, + // so we'll just always return true here. + .withComparatorForFields((a, b) -> 0, "floatBoxedList") + .withComparatorForType((a, b) -> Double.compare(a.doubleValue(), b.doubleValue()), Number.class) + .build(); + @Test public void test_insertAndQuery() throws Exception { short short_ = 666; int int_ = 666; - long long_ = 666L; - float float_ = 666f; - double double_ = 666d; + long long_ = 666; + float float_ = 666; + double double_ = 666; boolean boolean_ = true; UUID uuid = UUID.randomUUID(); OffsetDateTime date = OffsetDateTime.now(); @@ -216,12 +224,12 @@ public void test_insertAndQuery() throws Exception { var inserted = things.data.insert(thing); // Assert - var got = things.query.byId(inserted.uuid()); - Assertions.assertThat(got).get() - .extracting(WeaviateObject::properties, InstanceOfAssertFactories.type(Thing.class)); + var optional = things.query.byId(inserted.uuid()); + var got = Assertions.assertThat(optional).get() + .extracting(WeaviateObject::properties).actual(); - // TODO: add assertions; + Assertions.assertThat(got) + .usingRecursiveComparison(COMPARISON_CONFIG) + .isEqualTo(thing); } - - // TODO: insertMany (batch) } From 06eb0db8a6942cfa1caf90debb95baf5f166fea6 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 10 Sep 2025 17:51:58 +0200 Subject: [PATCH 08/13] test: add more assertions --- .../io/weaviate/integration/ORMITest.java | 86 +++++++++++++++++-- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index 52cfa436c..cee8bb8af 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -14,9 +14,10 @@ import io.weaviate.ConcurrentTest; import io.weaviate.client6.v1.api.WeaviateClient; import io.weaviate.client6.v1.api.collections.CollectionConfig; -import io.weaviate.client6.v1.api.collections.WeaviateObject; import io.weaviate.client6.v1.api.collections.annotations.Collection; import io.weaviate.client6.v1.api.collections.annotations.Property; +import io.weaviate.client6.v1.api.collections.data.InsertManyResponse.InsertObject; +import io.weaviate.client6.v1.api.collections.query.Where; import io.weaviate.containers.Container; public class ORMITest extends ConcurrentTest { @@ -224,12 +225,85 @@ public void test_insertAndQuery() throws Exception { var inserted = things.data.insert(thing); // Assert - var optional = things.query.byId(inserted.uuid()); - var got = Assertions.assertThat(optional).get() - .extracting(WeaviateObject::properties).actual(); - - Assertions.assertThat(got) + var got = things.query.byId(inserted.uuid()); + Assertions.assertThat(got).get() .usingRecursiveComparison(COMPARISON_CONFIG) .isEqualTo(thing); } + + @Test + public void test_insertManyAndQuery() throws Exception { + short short_ = 666; + int int_ = 666; + long long_ = 666; + float float_ = 666; + double double_ = 666; + boolean boolean_ = true; + UUID uuid = UUID.randomUUID(); + OffsetDateTime date = OffsetDateTime.now(); + String text = "hello"; + + var thing = new Thing( + text, + new String[] { text }, + List.of(text), + + OffsetDateTime.now(), + new OffsetDateTime[] { date }, + List.of(date), + + UUID.randomUUID(), + new UUID[] { uuid }, + List.of(uuid), + + short_, + short_, + new short[] { short_ }, + new Short[] { short_ }, + List.of(short_), + + int_, + int_, + new int[] { int_ }, + new Integer[] { int_ }, + List.of(int_), + + long_, + long_, + new long[] { long_ }, + new Long[] { long_ }, + List.of(long_), + + float_, + float_, + new float[] { float_ }, + new Float[] { float_ }, + List.of(float_), + + double_, + double_, + new double[] { double_ }, + new Double[] { double_ }, + List.of(double_), + + boolean_, + boolean_, + new boolean[] { boolean_ }, + new Boolean[] { boolean_ }, + List.of(boolean_)); + + var things = client.collections.use(Thing.class); + + // Act + var inserted = things.data.insertMany(thing, thing, thing); + + // Assert + var uuids = inserted.responses().stream().map(InsertObject::uuid).toArray(String[]::new); + var got = things.query.fetchObjects(q -> q.where(Where.uuid().containsAny(uuids))); + Assertions.assertThat(got.objects()) + .hasSize(3) + .usingRecursiveComparison(COMPARISON_CONFIG) + .asInstanceOf(InstanceOfAssertFactories.list(Thing.class)) + .contains(thing, thing, thing); + } } From c4a7280ca6d9c99e547788a09b527a7a77008736 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 10 Sep 2025 18:29:56 +0200 Subject: [PATCH 09/13] feat: support ORM in batching --- .../io/weaviate/integration/ORMITest.java | 3 +- .../collections/data/InsertManyRequest.java | 91 ++++++++++++++++++- .../client6/v1/internal/orm/PojoReader.java | 2 +- 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index cee8bb8af..adb27f876 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -303,7 +303,6 @@ public void test_insertManyAndQuery() throws Exception { Assertions.assertThat(got.objects()) .hasSize(3) .usingRecursiveComparison(COMPARISON_CONFIG) - .asInstanceOf(InstanceOfAssertFactories.list(Thing.class)) - .contains(thing, thing, thing); + .asInstanceOf(InstanceOfAssertFactories.list(Thing.class)); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java index 261a69064..79a978d32 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java @@ -1,5 +1,6 @@ package io.weaviate.client6.v1.api.collections.data; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -138,10 +139,98 @@ public static void buildObject(WeaviateProtoBatch.BatchObject.Builder object if (value instanceof String v) { protoValue.setStringValue(v); + } else if (value instanceof UUID v) { + protoValue.setStringValue(v.toString()); + } else if (value instanceof OffsetDateTime v) { + protoValue.setStringValue(v.toString()); + } else if (value instanceof Boolean v) { + protoValue.setBoolValue(v.booleanValue()); } else if (value instanceof Number v) { protoValue.setNumberValue(v.doubleValue()); + } else if (value instanceof List v) { + protoValue.setListValue( + com.google.protobuf.ListValue.newBuilder() + .addAllValues(v.stream() + .map(listValue -> { + var protoListValue = com.google.protobuf.Value.newBuilder(); + if (listValue instanceof String lv) { + protoListValue.setStringValue(lv); + } else if (listValue instanceof UUID lv) { + protoListValue.setStringValue(lv.toString()); + } else if (listValue instanceof OffsetDateTime lv) { + protoListValue.setStringValue(lv.toString()); + } else if (listValue instanceof Boolean lv) { + protoListValue.setBoolValue(lv); + } else if (listValue instanceof Number lv) { + protoListValue.setNumberValue(lv.doubleValue()); + } + return protoListValue.build(); + }) + .toList())); + + } else if (value.getClass().isArray()) { + List values; + + if (value instanceof String[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setStringValue(lv).build()).toList(); + } else if (value instanceof UUID[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setStringValue(lv.toString()).build()).toList(); + } else if (value instanceof OffsetDateTime[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setStringValue(lv.toString()).build()).toList(); + } else if (value instanceof Boolean[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setBoolValue(lv).build()).toList(); + } else if (value instanceof boolean[] v) { + values = new ArrayList<>(); + for (boolean b : v) { + values.add(com.google.protobuf.Value.newBuilder().setBoolValue(b).build()); + } + } else if (value instanceof short[] v) { + values = new ArrayList<>(); + for (short s : v) { + values.add(com.google.protobuf.Value.newBuilder().setNumberValue(s).build()); + } + } else if (value instanceof int[] v) { + values = Arrays.stream(v).boxed() + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof long[] v) { + values = Arrays.stream(v).boxed() + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof float[] v) { + values = new ArrayList<>(); + for (float s : v) { + values.add(com.google.protobuf.Value.newBuilder().setNumberValue(s).build()); + } + } else if (value instanceof double[] v) { + values = Arrays.stream(v).boxed() + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof Short[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof Integer[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof Long[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof Float[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else if (value instanceof Double[] v) { + values = Arrays.stream(v) + .map(lv -> com.google.protobuf.Value.newBuilder().setNumberValue(lv).build()).toList(); + } else { + throw new AssertionError("(insertMany) branch not covered " + value.getClass()); + } + + protoValue.setListValue(com.google.protobuf.ListValue.newBuilder() + .addAllValues(values) + .build()); } else { - assert false : "(insertMany) branch not covered"; + throw new AssertionError("(insertMany) branch not covered " + value.getClass()); } nonRef.putFields(entry.getKey(), protoValue.build()); diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java index da3ceb75f..82ccea5a3 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoReader.java @@ -14,7 +14,7 @@ final class PojoReader implements PropertiesReader { public Map readProperties() { var out = new HashMap(); for (var field : properties.getClass().getDeclaredFields()) { - var propertyName = field.getName(); + var propertyName = PojoDescriptor.propertyName(field); field.setAccessible(true); try { out.put(propertyName, field.get(properties)); From 35e6a1c67601c6fdbf471f278b82adf9db2c6222 Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Wed, 10 Sep 2025 19:07:54 +0200 Subject: [PATCH 10/13] test: fix asssertion target --- src/it/java/io/weaviate/integration/ORMITest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/it/java/io/weaviate/integration/ORMITest.java b/src/it/java/io/weaviate/integration/ORMITest.java index adb27f876..d46d1600c 100644 --- a/src/it/java/io/weaviate/integration/ORMITest.java +++ b/src/it/java/io/weaviate/integration/ORMITest.java @@ -225,8 +225,10 @@ public void test_insertAndQuery() throws Exception { var inserted = things.data.insert(thing); // Assert - var got = things.query.byId(inserted.uuid()); - Assertions.assertThat(got).get() + var response = things.query.byId(inserted.uuid()); + var got = Assertions.assertThat(response).get().actual(); + + Assertions.assertThat(got.properties()) .usingRecursiveComparison(COMPARISON_CONFIG) .isEqualTo(thing); } From 8b8418b27923bf81501601aebf3427409f6a147a Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 16 Sep 2025 14:31:48 +0200 Subject: [PATCH 11/13] feat: extend WeaviateCollectionsClientAsync to support ORM methods --- .../WeaviateCollectionsClient.java | 100 ++++++++++-- .../WeaviateCollectionsClientAsync.java | 150 ++++++++++++++++-- .../collections/annotations/Collection.java | 2 + .../api/collections/annotations/Property.java | 1 + .../api/collections/pagination/Paginator.java | 2 +- .../client6/v1/internal/ObjectBuilder.java | 5 +- .../v1/internal/orm/CollectionDescriptor.java | 6 + 7 files changed, 238 insertions(+), 28 deletions(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java index 088bd2403..55be32980 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java @@ -21,6 +21,14 @@ public WeaviateCollectionsClient(RestTransport restTransport, GrpcTransport grpc this.grpcTransport = grpcTransport; } + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param cls Class that represents an object in the collection. + * @return a handle for a collection with {@code Class} + * properties. + */ public CollectionHandle use(Class cls) { return use(CollectionDescriptor.ofClass(cls), CollectionHandleDefaults.none()); } @@ -29,6 +37,22 @@ public CollectionHandle use(Class} + * properties. + */ + public CollectionHandle use( + Class cls, + Function> fn) { + return use(CollectionDescriptor.ofClass(cls), fn); + } + + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param collectionName Name of the collection. * @return a handle for a collection with {@code Map} * properties. */ @@ -40,6 +64,8 @@ public CollectionHandle> use(String collectionName) { * Obtain a handle to send requests to a particular collection. * The returned object is thread-safe. * + * @param collectionName Name of the collection. + * @param fn Lamda expression for optional parameters. * @return a handle for a collection with {@code Map} * properties. */ @@ -54,14 +80,63 @@ private CollectionHandle use(CollectionDescriptor(restTransport, grpcTransport, collection, CollectionHandleDefaults.of(fn)); } + /** + * Create a new Weaviate collection with default configuration. + * + *
{@code
+   * // Define a record class that represents an object in collection.
+   * record Song(
+   *  String title;
+   *  int yearReleased;
+   *  String[] genres;
+   * ) {}
+   *
+   * client.collections.create(Song.class);
+   * }
+ * + * @param cls Class that represents an object in the collection. + * @return the configuration of the created collection. + * @throws WeaviateApiException in case the server returned with an + * error status code. + * @throws IOException in case the request was not sent successfully + * due to a malformed request, a networking error + * or the server being unavailable. + * @see io.weaviate.client6.v1.api.collections.annotations.Collection + * @see io.weaviate.client6.v1.api.collections.annotations.Property + */ public CollectionConfig create(Class cls) throws IOException { var collection = CollectionDescriptor.ofClass(cls); return create(CollectionConfig.of(collection.name(), collection.configFn())); } + /** + * Create and configure a new Weaviate collection. See + * {@link CollectionConfig.Builder} for available options. + * + * @param cls Class that represents an object in the collection. + * @param fn Lamda expression for optional parameters. + * @return the configuration of the created collection. + * @throws WeaviateApiException in case the server returned with an + * error status code. + * @throws IOException in case the request was not sent successfully + * due to a malformed request, a networking error + * or the server being unavailable. + * @see io.weaviate.client6.v1.api.collections.annotations.Collection + * @see io.weaviate.client6.v1.api.collections.annotations.Property + * @see WeaviateCollectionsClient#create(Class) + */ + public CollectionConfig create( + Class cls, + Function> fn) throws IOException { + var collection = CollectionDescriptor.ofClass(cls); + var configFn = ObjectBuilder.partial(fn, collection.configFn()); + return create(CollectionConfig.of(collection.name(), configFn)); + } + /** * Create a new Weaviate collection with default configuration. * + * @param collectionName Collection name. * @return the configuration of the created collection. * @throws WeaviateApiException in case the server returned with an * error status code. @@ -69,14 +144,16 @@ public CollectionConfig create(Class c * due to a malformed request, a networking error * or the server being unavailable. */ - public CollectionConfig create(String name) throws IOException { - return create(CollectionConfig.of(name)); + public CollectionConfig create(String collectionName) throws IOException { + return create(CollectionConfig.of(collectionName)); } /** * Create and configure a new Weaviate collection. See * {@link CollectionConfig.Builder} for available options. * + * @param collectionName Collection name. + * @param fn Lamda expression for optional parameters. * @return the configuration of the created collection. * @throws WeaviateApiException in case the server returned with an * error status code. @@ -84,9 +161,9 @@ public CollectionConfig create(String name) throws IOException { * due to a malformed request, a networking error * or the server being unavailable. */ - public CollectionConfig create(String name, + public CollectionConfig create(String collectionName, Function> fn) throws IOException { - return create(CollectionConfig.of(name, fn)); + return create(CollectionConfig.of(collectionName, fn)); } /** @@ -107,6 +184,7 @@ public CollectionConfig create(CollectionConfig collection) throws IOException { /** * Fetch Weaviate collection configuration. * + * @param collectionName Collection name. * @return the collection configuration if one with this name exists. * @throws WeaviateApiException in case the server returned with an * error status code. @@ -114,8 +192,8 @@ public CollectionConfig create(CollectionConfig collection) throws IOException { * due to a malformed request, a networking error * or the server being unavailable. */ - public Optional getConfig(String name) throws IOException { - return this.restTransport.performRequest(new GetConfigRequest(name), GetConfigRequest._ENDPOINT); + public Optional getConfig(String collectionName) throws IOException { + return this.restTransport.performRequest(new GetConfigRequest(collectionName), GetConfigRequest._ENDPOINT); } /** @@ -135,14 +213,15 @@ public List list() throws IOException { /** * Delete a Weaviate collection. * + * @param collectionName Collection name. * @throws WeaviateApiException in case the server returned with an * error status code. * @throws IOException in case the request was not sent successfully * due to a malformed request, a networking error * or the server being unavailable. */ - public void delete(String name) throws IOException { - this.restTransport.performRequest(new DeleteCollectionRequest(name), DeleteCollectionRequest._ENDPOINT); + public void delete(String collectionName) throws IOException { + this.restTransport.performRequest(new DeleteCollectionRequest(collectionName), DeleteCollectionRequest._ENDPOINT); } /** @@ -163,13 +242,14 @@ public void deleteAll() throws IOException { /** * Check if a collection with this name exists. * + * @param collectionName Collection name. * @throws WeaviateApiException in case the server returned with an * error status code. * @throws IOException in case the request was not sent successfully * due to a malformed request, a networking error * or the server being unavailable. */ - public boolean exists(String name) throws IOException { - return getConfig(name).isPresent(); + public boolean exists(String collectionName) throws IOException { + return getConfig(collectionName).isPresent(); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java index 4fc449cf1..b7c5a68e3 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java @@ -21,46 +21,161 @@ public WeaviateCollectionsClientAsync(RestTransport restTransport, GrpcTransport this.grpcTransport = grpcTransport; } + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param cls Class that represents an object in the collection. + * @return a handle for a collection with {@code Class} + * properties. + */ + public CollectionHandleAsync use(Class cls) { + return use(CollectionDescriptor.ofClass(cls), CollectionHandleDefaults.none()); + } + + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param cls Class that represents an object in the collection. + * @param fn Lamda expression for optional parameters. + * @return a handle for a collection with {@code Class} + * properties. + */ + public CollectionHandleAsync use( + Class cls, + Function> fn) { + return use(CollectionDescriptor.ofClass(cls), fn); + } + + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param collectionName Name of the collection. + * @return a handle for a collection with {@code Map} + * properties. + */ public CollectionHandleAsync> use(String collectionName) { return use(collectionName, CollectionHandleDefaults.none()); } + /** + * Obtain a handle to send requests to a particular collection. + * The returned object is thread-safe. + * + * @param collectionName Name of the collection. + * @param fn Lamda expression for optional parameters. + * @return a handle for a collection with {@code Map} + * properties. + */ public CollectionHandleAsync> use( String collectionName, Function> fn) { - return new CollectionHandleAsync<>( - restTransport, - grpcTransport, - CollectionDescriptor.ofMap(collectionName), - CollectionHandleDefaults.of(fn)); + return use(CollectionDescriptor.ofMap(collectionName), fn); + } + + private CollectionHandleAsync use(CollectionDescriptor collection, + Function> fn) { + return new CollectionHandleAsync<>(restTransport, grpcTransport, collection, CollectionHandleDefaults.of(fn)); + } + + /** + * Create a new Weaviate collection with default configuration. + * + *
{@code
+   * // Define a record class that represents an object in collection.
+   * record Song(
+   *  String title;
+   *  int yearReleased;
+   *  String[] genres;
+   * ) {}
+   *
+   * client.collections.create(Song.class);
+   * }
+ * + * @param cls Class that represents an object in the collection. + * @see io.weaviate.client6.v1.api.collections.annotations.Collection + * @see io.weaviate.client6.v1.api.collections.annotations.Property + */ + public CompletableFuture create(Class cls) { + var collection = CollectionDescriptor.ofClass(cls); + return create(CollectionConfig.of(collection.name(), collection.configFn())); + } + + /** + * Create and configure a new Weaviate collection. See + * {@link CollectionConfig.Builder} for available options. + * + * @param cls Class that represents an object in the collection. + * @param fn Lamda expression for optional parameters. + * @see io.weaviate.client6.v1.api.collections.annotations.Collection + * @see io.weaviate.client6.v1.api.collections.annotations.Property + * @see WeaviateCollectionsClientAsync#create(Class) + */ + public CompletableFuture create(Class cls, + Function> fn) { + var collection = CollectionDescriptor.ofClass(cls); + var configFn = ObjectBuilder.partial(fn, collection.configFn()); + return create(CollectionConfig.of(collection.name(), configFn)); } - public CompletableFuture create(String name) { - return create(CollectionConfig.of(name)); + /** + * Create a new Weaviate collection with default configuration. + * + * @param collectionName Collection name. + * @return the configuration of the created collection. + */ + public CompletableFuture create(String collectionName) { + return create(CollectionConfig.of(collectionName)); } - public CompletableFuture create(String name, + /** + * Create and configure a new Weaviate collection. See + * {@link CollectionConfig.Builder} for available options. + * + * @param collectionName Collection name. + * @param fn Lamda expression for optional parameters. + */ + public CompletableFuture create(String collectionName, Function> fn) { - return create(CollectionConfig.of(name, fn)); + return create(CollectionConfig.of(collectionName, fn)); } + /** + * Create a new Weaviate collection with {@link CollectionConfig}. + */ public CompletableFuture create(CollectionConfig collection) { return this.restTransport.performRequestAsync(new CreateCollectionRequest(collection), CreateCollectionRequest._ENDPOINT); } - public CompletableFuture> getConfig(String name) { - return this.restTransport.performRequestAsync(new GetConfigRequest(name), GetConfigRequest._ENDPOINT); + /** + * Fetch Weaviate collection configuration. + * + * @param collectionName Collection name. + */ + public CompletableFuture> getConfig(String collectionName) { + return this.restTransport.performRequestAsync(new GetConfigRequest(collectionName), GetConfigRequest._ENDPOINT); } public CompletableFuture> list() { return this.restTransport.performRequestAsync(new ListCollectionRequest(), ListCollectionRequest._ENDPOINT); } - public CompletableFuture delete(String name) { - return this.restTransport.performRequestAsync(new DeleteCollectionRequest(name), DeleteCollectionRequest._ENDPOINT); + /** + * Delete a Weaviate collection. + * + * @param collectionName Collection name. + */ + public CompletableFuture delete(String collectionName) { + return this.restTransport.performRequestAsync(new DeleteCollectionRequest(collectionName), + DeleteCollectionRequest._ENDPOINT); } + /** + * Delete all collections in Weaviate. + */ public CompletableFuture deleteAll() throws IOException { return list().thenCompose(collections -> { var futures = collections.stream() @@ -70,7 +185,12 @@ public CompletableFuture deleteAll() throws IOException { }); } - public CompletableFuture exists(String name) { - return getConfig(name).thenApply(Optional::isPresent); + /** + * Check if a collection with this name exists. + * + * @param collectionName Collection name. + */ + public CompletableFuture exists(String collectionName) { + return getConfig(collectionName).thenApply(Optional::isPresent); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java index 9cb20d4a0..4256c95ef 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Collection.java @@ -8,7 +8,9 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Collection { + /** The name of the collection mapped by this class. */ String value(); + /** Collection description to add on creation. */ String description() default ""; } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java index 9dbd6118f..89275bc1d 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/annotations/Property.java @@ -8,5 +8,6 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Property { + /** The name of the propety mapped by the record's field. */ String value(); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java index 04b10bf11..dfc7c90ca 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/Paginator.java @@ -111,7 +111,7 @@ public final Builder returnMetadata(List metadata) { return applyQueryOption(q -> q.returnMetadata(metadata)); } - private final Builder applyQueryOption(Function options) { + private final Builder applyQueryOption(Function> options) { this.queryOptions = ObjectBuilder.partial(this.queryOptions, options); return this; } diff --git a/src/main/java/io/weaviate/client6/v1/internal/ObjectBuilder.java b/src/main/java/io/weaviate/client6/v1/internal/ObjectBuilder.java index a1ed410fc..b138326ea 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/ObjectBuilder.java +++ b/src/main/java/io/weaviate/client6/v1/internal/ObjectBuilder.java @@ -28,8 +28,9 @@ static , T> Function> identity() * @param partialFn Function that will be applied first. * @return ObjectBuilder with "pre-applied" function. */ + @SuppressWarnings("unchecked") static , T> Function> partial(Function> fn, - Function partialFn) { - return partialFn.andThen(fn); + Function> partialFn) { + return partialFn.andThen(b -> fn.apply((B) b)); } } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java index c202ab9f9..e4355c3a7 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java @@ -21,6 +21,12 @@ default Function> conf return ObjectBuilder.identity(); } + // default Function> + // partial( + // Function> fn) { + // return configFn().andThen(b -> fn.apply((CollectionConfig.Builder) b)); + // } + static CollectionDescriptor> ofMap(String collectionName) { return new MapDescriptor(collectionName); } From 7bcb97d55ea904f7d1a3c58cd1df9c58ad580c0c Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 16 Sep 2025 14:34:10 +0200 Subject: [PATCH 12/13] chore: apply collection description option --- .../v1/api/collections/pagination/AsyncPaginator.java | 3 ++- .../weaviate/client6/v1/internal/orm/PojoDescriptor.java | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java index 771b6e4b6..972f07a4f 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/pagination/AsyncPaginator.java @@ -154,7 +154,8 @@ public final Builder returnMetadata(List metadata) { return applyQueryOption(q -> q.returnMetadata(metadata)); } - private final Builder applyQueryOption(Function options) { + private final Builder applyQueryOption( + Function> options) { this.queryOptions = ObjectBuilder.partial(this.queryOptions, options); return this; } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index ee9b01112..fbc66ec1b 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -126,7 +126,12 @@ public Function> confi } private ObjectBuilder inspectClass(CollectionConfig.Builder b) { - // Add properties; + var annotation = cls.getAnnotation(Collection.class); + if (annotation != null) { + b.description(annotation.description()); + } + + // Add properties for (var field : cls.getDeclaredFields()) { var propertyName = propertyName(field); Function ctor; From c87e3eb8f2a883ee016847e0822bec66ebb3495f Mon Sep 17 00:00:00 2001 From: dyma solovei Date: Tue, 16 Sep 2025 14:42:33 +0200 Subject: [PATCH 13/13] chore: rename CollectionDescriptor::name -> CollectionDescriptor::collectionName --- .../v1/api/collections/WeaviateCollectionsClient.java | 4 ++-- .../api/collections/WeaviateCollectionsClientAsync.java | 4 ++-- .../v1/api/collections/aggregate/AggregateRequest.java | 4 ++-- .../v1/api/collections/config/GetShardsRequest.java | 2 +- .../v1/api/collections/config/WeaviateConfigClient.java | 6 +++--- .../api/collections/config/WeaviateConfigClientAsync.java | 6 +++--- .../v1/api/collections/data/DeleteManyRequest.java | 2 +- .../v1/api/collections/data/DeleteObjectRequest.java | 2 +- .../v1/api/collections/data/InsertManyRequest.java | 2 +- .../v1/api/collections/data/ReferenceAddRequest.java | 3 ++- .../v1/api/collections/data/ReferenceDeleteRequest.java | 3 ++- .../v1/api/collections/data/ReferenceReplaceRequest.java | 3 ++- .../v1/api/collections/data/ReplaceObjectRequest.java | 2 +- .../v1/api/collections/data/UpdateObjectRequest.java | 2 +- .../v1/api/collections/data/WeaviateDataClient.java | 8 ++++---- .../v1/api/collections/data/WeaviateDataClientAsync.java | 8 ++++---- .../client6/v1/api/collections/query/QueryRequest.java | 7 ++++--- .../v1/api/collections/tenants/CreateTenantsRequest.java | 2 +- .../v1/api/collections/tenants/DeleteTenantsRequest.java | 2 +- .../v1/api/collections/tenants/GetTenantsRequest.java | 2 +- .../v1/api/collections/tenants/TenantExistsRequest.java | 2 +- .../v1/api/collections/tenants/UpdateTenantsRequest.java | 2 +- .../client6/v1/internal/orm/CollectionDescriptor.java | 8 +------- .../weaviate/client6/v1/internal/orm/MapDescriptor.java | 2 +- .../weaviate/client6/v1/internal/orm/PojoDescriptor.java | 2 +- 25 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java index 55be32980..2bcb3071d 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClient.java @@ -106,7 +106,7 @@ private CollectionHandle use(CollectionDescriptor CollectionConfig create(Class cls) throws IOException { var collection = CollectionDescriptor.ofClass(cls); - return create(CollectionConfig.of(collection.name(), collection.configFn())); + return create(CollectionConfig.of(collection.collectionName(), collection.configFn())); } /** @@ -130,7 +130,7 @@ public CollectionConfig create( Function> fn) throws IOException { var collection = CollectionDescriptor.ofClass(cls); var configFn = ObjectBuilder.partial(fn, collection.configFn()); - return create(CollectionConfig.of(collection.name(), configFn)); + return create(CollectionConfig.of(collection.collectionName(), configFn)); } /** diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java index b7c5a68e3..e7e4755b3 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/WeaviateCollectionsClientAsync.java @@ -100,7 +100,7 @@ private CollectionHandleAsync use(CollectionDescripto */ public CompletableFuture create(Class cls) { var collection = CollectionDescriptor.ofClass(cls); - return create(CollectionConfig.of(collection.name(), collection.configFn())); + return create(CollectionConfig.of(collection.collectionName(), collection.configFn())); } /** @@ -117,7 +117,7 @@ public CompletableFuture create(C Function> fn) { var collection = CollectionDescriptor.ofClass(cls); var configFn = ObjectBuilder.partial(fn, collection.configFn()); - return create(CollectionConfig.of(collection.name(), configFn)); + return create(CollectionConfig.of(collection.collectionName(), configFn)); } /** diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/aggregate/AggregateRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/aggregate/AggregateRequest.java index 75d3046c9..89e891cf1 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/aggregate/AggregateRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/aggregate/AggregateRequest.java @@ -20,10 +20,10 @@ static Rpc { var message = WeaviateProtoAggregate.AggregateRequest.newBuilder(); - message.setCollection(collection.name()); + message.setCollection(collection.collectionName()); request.aggregation.appendTo(message); if (request.groupBy != null) { - request.groupBy.appendTo(message, collection.name()); + request.groupBy.appendTo(message, collection.collectionName()); } if (defaults.tenant() != null) { message.setTenant(defaults.tenant()); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/config/GetShardsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/config/GetShardsRequest.java index d04ccfbcf..5237fed26 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/config/GetShardsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/config/GetShardsRequest.java @@ -20,7 +20,7 @@ public static final Endpoint> endpoint( CollectionHandleDefaults defaults) { return SimpleEndpoint.noBody( request -> "GET", - request -> "/schema/" + collection.name() + "/shards", + request -> "/schema/" + collection.collectionName() + "/shards", request -> defaults.tenant() != null ? Map.of("tenant", defaults.tenant()) : Collections.emptyMap(), diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClient.java index fdc957f01..3a5ab706f 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClient.java @@ -43,11 +43,11 @@ public WeaviateConfigClient(WeaviateConfigClient c, CollectionHandleDefaults def } public Optional get() throws IOException { - return collectionsClient.getConfig(collection.name()); + return collectionsClient.getConfig(collection.collectionName()); } public void addProperty(Property property) throws IOException { - this.restTransport.performRequest(new AddPropertyRequest(collection.name(), property), + this.restTransport.performRequest(new AddPropertyRequest(collection.collectionName(), property), AddPropertyRequest._ENDPOINT); } @@ -73,7 +73,7 @@ public List updateShards(ShardStatus status, String... shards) throws IOE public List updateShards(ShardStatus status, List shards) throws IOException { for (var shard : shards) { this.restTransport.performRequest( - new UpdateShardStatusRequest(collection.name(), shard, status), + new UpdateShardStatusRequest(collection.collectionName(), shard, status), UpdateShardStatusRequest._ENDPOINT); } return getShards(); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClientAsync.java index 34d6a66a6..b17ad26f2 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/config/WeaviateConfigClientAsync.java @@ -44,11 +44,11 @@ public WeaviateConfigClientAsync(WeaviateConfigClientAsync c, CollectionHandleDe } public CompletableFuture> get() throws IOException { - return collectionsClient.getConfig(collection.name()); + return collectionsClient.getConfig(collection.collectionName()); } public CompletableFuture addProperty(Property property) throws IOException { - return this.restTransport.performRequestAsync(new AddPropertyRequest(collection.name(), property), + return this.restTransport.performRequestAsync(new AddPropertyRequest(collection.collectionName(), property), AddPropertyRequest._ENDPOINT); } @@ -76,7 +76,7 @@ public CompletableFuture> updateShards(ShardStatus status, String... public CompletableFuture> updateShards(ShardStatus status, List shards) throws IOException { var updates = shards.stream().map( shard -> this.restTransport.performRequestAsync( - new UpdateShardStatusRequest(collection.name(), shard, status), + new UpdateShardStatusRequest(collection.collectionName(), shard, status), UpdateShardStatusRequest._ENDPOINT)) .toArray(CompletableFuture[]::new); return CompletableFuture.allOf(updates).thenCompose(__ -> getShards()); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java index a472b918a..4698157ab 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteManyRequest.java @@ -21,7 +21,7 @@ public static Rpc { var message = WeaviateProtoBatchDelete.BatchDeleteRequest.newBuilder(); - message.setCollection(collection.name()); + message.setCollection(collection.collectionName()); if (request.verbose != null) { message.setVerbose(request.verbose); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteObjectRequest.java index 307dfd04f..0bb205cdd 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/DeleteObjectRequest.java @@ -12,7 +12,7 @@ public static final Endpoint endpoint( CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "DELETE", - request -> "/objects/" + collection.name() + "/" + request.uuid, + request -> "/objects/" + collection.collectionName() + "/" + request.uuid, request -> defaults.queryParameters()); } } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java index 79a978d32..c8a12fa0c 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/InsertManyRequest.java @@ -94,7 +94,7 @@ public static void buildObject(WeaviateProtoBatch.BatchObject.Builder object WeaviateObject insert, CollectionDescriptor collection, CollectionHandleDefaults defaults) { - object.setCollection(collection.name()); + object.setCollection(collection.collectionName()); var metadata = insert.metadata(); if (metadata != null) { diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java index 89201f4de..21321327f 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceAddRequest.java @@ -13,7 +13,8 @@ public static final Endpoint endpoint( CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "POST", - request -> "/objects/" + descriptor.name() + "/" + request.fromUuid + "/references/" + request.fromProperty, + request -> "/objects/" + descriptor.collectionName() + "/" + request.fromUuid + "/references/" + + request.fromProperty, request -> defaults.queryParameters(), request -> JSON.serialize(request.reference)); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java index fc53457ae..9144f2b2f 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceDeleteRequest.java @@ -13,7 +13,8 @@ public static final Endpoint endpoint( CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "DELETE", - request -> "/objects/" + descriptor.name() + "/" + request.fromUuid + "/references/" + request.fromProperty, + request -> "/objects/" + descriptor.collectionName() + "/" + request.fromUuid + "/references/" + + request.fromProperty, request -> defaults.queryParameters(), request -> JSON.serialize(request.reference)); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java index 13516d0ac..3bf7b1e30 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReferenceReplaceRequest.java @@ -15,7 +15,8 @@ public static final Endpoint endpoint( CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "PUT", - request -> "/objects/" + descriptor.name() + "/" + request.fromUuid + "/references/" + request.fromProperty, + request -> "/objects/" + descriptor.collectionName() + "/" + request.fromUuid + "/references/" + + request.fromProperty, request -> defaults.queryParameters(), request -> JSON.serialize(List.of(request.reference))); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java index 0a786e1e2..2a3257d14 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/ReplaceObjectRequest.java @@ -22,7 +22,7 @@ static final Endpoint, Void> endpoint(CollectionDesc CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "PUT", - request -> "/objects/" + collection.name() + "/" + request.object.metadata().uuid(), + request -> "/objects/" + collection.collectionName() + "/" + request.object.metadata().uuid(), request -> defaults.consistencyLevel() != null ? Map.of("consistency_level", defaults.consistencyLevel()) : Collections.emptyMap(), diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java index 2d0a76d78..c174e05eb 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/UpdateObjectRequest.java @@ -22,7 +22,7 @@ static final Endpoint, Void> endpoint(CollectionDescr CollectionHandleDefaults defaults) { return SimpleEndpoint.sideEffect( request -> "PATCH", - request -> "/objects/" + collection.name() + "/" + request.object.metadata().uuid(), + request -> "/objects/" + collection.collectionName() + "/" + request.object.metadata().uuid(), request -> defaults.consistencyLevel() != null ? Map.of("consistency_level", defaults.consistencyLevel()) : Collections.emptyMap(), diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java index 1455b8638..82cce27a6 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClient.java @@ -46,13 +46,13 @@ public WeaviateDataClient(WeaviateDataClient c, CollectionHandleDef } public WeaviateObject insert(PropertiesT properties) throws IOException { - return insert(InsertObjectRequest.of(collection.name(), properties)); + return insert(InsertObjectRequest.of(collection.collectionName(), properties)); } public WeaviateObject insert(PropertiesT properties, Function, ObjectBuilder>> fn) throws IOException { - return insert(InsertObjectRequest.of(collection.name(), properties, fn)); + return insert(InsertObjectRequest.of(collection.collectionName(), properties, fn)); } @SafeVarargs @@ -81,14 +81,14 @@ public boolean exists(String uuid) { public void update(String uuid, Function, ObjectBuilder>> fn) throws IOException { - this.restTransport.performRequest(UpdateObjectRequest.of(collection.name(), uuid, fn), + this.restTransport.performRequest(UpdateObjectRequest.of(collection.collectionName(), uuid, fn), UpdateObjectRequest.endpoint(collection, defaults)); } public void replace(String uuid, Function, ObjectBuilder>> fn) throws IOException { - this.restTransport.performRequest(ReplaceObjectRequest.of(collection.name(), uuid, fn), + this.restTransport.performRequest(ReplaceObjectRequest.of(collection.collectionName(), uuid, fn), ReplaceObjectRequest.endpoint(collection, defaults)); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java index f85696a5f..6aae3bb41 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/data/WeaviateDataClientAsync.java @@ -48,12 +48,12 @@ public WeaviateDataClientAsync(WeaviateDataClientAsync c, Collectio } public CompletableFuture> insert(PropertiesT properties) { - return insert(InsertObjectRequest.of(collection.name(), properties)); + return insert(InsertObjectRequest.of(collection.collectionName(), properties)); } public CompletableFuture> insert(PropertiesT properties, Function, ObjectBuilder>> fn) { - return insert(InsertObjectRequest.of(collection.name(), properties, fn)); + return insert(InsertObjectRequest.of(collection.collectionName(), properties, fn)); } public CompletableFuture> insert( @@ -82,13 +82,13 @@ public CompletableFuture exists(String uuid) { public CompletableFuture update(String uuid, Function, ObjectBuilder>> fn) { - return this.restTransport.performRequestAsync(UpdateObjectRequest.of(collection.name(), uuid, fn), + return this.restTransport.performRequestAsync(UpdateObjectRequest.of(collection.collectionName(), uuid, fn), UpdateObjectRequest.endpoint(collection, defaults)); } public CompletableFuture replace(String uuid, Function, ObjectBuilder>> fn) { - return this.restTransport.performRequestAsync(ReplaceObjectRequest.of(collection.name(), uuid, fn), + return this.restTransport.performRequestAsync(ReplaceObjectRequest.of(collection.collectionName(), uuid, fn), ReplaceObjectRequest.endpoint(collection, defaults)); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryRequest.java index f38ef3b26..9f42be010 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/query/QueryRequest.java @@ -34,7 +34,7 @@ static Rpc WeaviateObject unmarshalResultObjec if (metadataResult.getExplainScorePresent()) { metadata.explainScore(metadataResult.getExplainScore()); } - return new WeaviateObject<>(collection.name(), object.properties(), object.references(), metadata.build()); + return new WeaviateObject<>(collection.collectionName(), object.properties(), object.references(), + metadata.build()); } private static WeaviateObject unmarshalWithReferences( @@ -198,7 +199,7 @@ private static WeaviateObject unmarshalWithRefere } var obj = new WeaviateObject.Builder() - .collection(descriptor.name()) + .collection(descriptor.collectionName()) .properties(properties.build()) .references(referenceProperties) .metadata(metadata); diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/CreateTenantsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/CreateTenantsRequest.java index ea740e68c..aa72ede5f 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/CreateTenantsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/CreateTenantsRequest.java @@ -12,7 +12,7 @@ public record CreateTenantsRequest(List tenants) { static Endpoint endpoint(CollectionDescriptor collection) { return SimpleEndpoint.sideEffect( __ -> "POST", - __ -> "/schema/" + collection.name() + "/tenants", + __ -> "/schema/" + collection.collectionName() + "/tenants", __ -> Collections.emptyMap(), request -> JSON.serialize(request.tenants)); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/DeleteTenantsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/DeleteTenantsRequest.java index 82f499314..82f956ff7 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/DeleteTenantsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/DeleteTenantsRequest.java @@ -12,7 +12,7 @@ public record DeleteTenantsRequest(List tenants) { static Endpoint endpoint(CollectionDescriptor collection) { return SimpleEndpoint.sideEffect( __ -> "DELETE", - __ -> "/schema/" + collection.name() + "/tenants", + __ -> "/schema/" + collection.collectionName() + "/tenants", __ -> Collections.emptyMap(), request -> JSON.serialize(request.tenants)); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/GetTenantsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/GetTenantsRequest.java index a8095ed1b..1219c45c6 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/GetTenantsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/GetTenantsRequest.java @@ -15,7 +15,7 @@ static final Rpc { var message = WeaviateProtoTenants.TenantsGetRequest.newBuilder() - .setCollection(collection.name()); + .setCollection(collection.collectionName()); if (!request.tenants.isEmpty()) { message.setNames(TenantNames.newBuilder() diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/TenantExistsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/TenantExistsRequest.java index 50e238457..74445af29 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/TenantExistsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/TenantExistsRequest.java @@ -10,7 +10,7 @@ public record TenantExistsRequest(String tenant) { static Endpoint endpoint(CollectionDescriptor collection) { return new BooleanEndpoint<>( __ -> "GET", - request -> "/schema/" + collection.name() + "/tenants/" + request.tenant, + request -> "/schema/" + collection.collectionName() + "/tenants/" + request.tenant, __ -> Collections.emptyMap(), __ -> null); } diff --git a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/UpdateTenantsRequest.java b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/UpdateTenantsRequest.java index 37f40be00..c17334be0 100644 --- a/src/main/java/io/weaviate/client6/v1/api/collections/tenants/UpdateTenantsRequest.java +++ b/src/main/java/io/weaviate/client6/v1/api/collections/tenants/UpdateTenantsRequest.java @@ -12,7 +12,7 @@ public record UpdateTenantsRequest(List tenants) { static Endpoint endpoint(CollectionDescriptor collection) { return SimpleEndpoint.sideEffect( __ -> "PUT", - __ -> "/schema/" + collection.name() + "/tenants", + __ -> "/schema/" + collection.collectionName() + "/tenants", __ -> Collections.emptyMap(), request -> JSON.serialize(request.tenants)); } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java index e4355c3a7..de7ca31a0 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/CollectionDescriptor.java @@ -9,7 +9,7 @@ import io.weaviate.client6.v1.internal.ObjectBuilder; public sealed interface CollectionDescriptor permits MapDescriptor, PojoDescriptor { - String name(); + String collectionName(); TypeToken typeToken(); @@ -21,12 +21,6 @@ default Function> conf return ObjectBuilder.identity(); } - // default Function> - // partial( - // Function> fn) { - // return configFn().andThen(b -> fn.apply((CollectionConfig.Builder) b)); - // } - static CollectionDescriptor> ofMap(String collectionName) { return new MapDescriptor(collectionName); } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/MapDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/MapDescriptor.java index 2910f2db4..1d7549a76 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/MapDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/MapDescriptor.java @@ -12,7 +12,7 @@ public MapDescriptor(String collectionName) { } @Override - public String name() { + public String collectionName() { return collectionName; } diff --git a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java index fbc66ec1b..bcb1b4703 100644 --- a/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java +++ b/src/main/java/io/weaviate/client6/v1/internal/orm/PojoDescriptor.java @@ -97,7 +97,7 @@ String fieldName(String propertyName) { } @Override - public String name() { + public String collectionName() { var annotation = cls.getAnnotation(Collection.class); if (annotation != null) { return annotation.value();