diff --git a/src/main/java/io/weaviate/client/base/util/CrossReference.java b/src/main/java/io/weaviate/client/base/util/CrossReference.java new file mode 100644 index 00000000..f0f33f13 --- /dev/null +++ b/src/main/java/io/weaviate/client/base/util/CrossReference.java @@ -0,0 +1,38 @@ +package io.weaviate.client.base.util; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.ToString; +import lombok.experimental.FieldDefaults; +import org.apache.commons.lang3.StringUtils; + +@ToString +@Getter +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +public class CrossReference { + String peerName; + String className; + String targetID; + boolean local; + + public CrossReference(String peerName, String className, String targetID) { + this.local = peerName != null && peerName.equals("localhost"); + this.peerName = peerName; + this.className = className; + this.targetID = targetID; + } + + public static CrossReference fromBeacon(String beacon) { + if (StringUtils.isNotBlank(beacon) && beacon.startsWith("weaviate://")) { + String path = beacon.replaceFirst("weaviate://", ""); + String[] parts = path.split("/"); + if (parts.length == 3) { + return new CrossReference(parts[0], parts[1], parts[2]); + } + if (parts.length == 2) { + return new CrossReference(parts[0], "", parts[1]); + } + } + return null; + } +} diff --git a/src/main/java/io/weaviate/client/v1/batch/grpc/BatchObjectConverter.java b/src/main/java/io/weaviate/client/v1/batch/grpc/BatchObjectConverter.java index 50b2bb14..9c3df918 100644 --- a/src/main/java/io/weaviate/client/v1/batch/grpc/BatchObjectConverter.java +++ b/src/main/java/io/weaviate/client/v1/batch/grpc/BatchObjectConverter.java @@ -2,9 +2,10 @@ import com.google.protobuf.Struct; import com.google.protobuf.Value; -import io.weaviate.client.v1.data.model.WeaviateObject; +import io.weaviate.client.base.util.CrossReference; import io.weaviate.client.grpc.protocol.v1.WeaviateProtoBase; import io.weaviate.client.grpc.protocol.v1.WeaviateProtoBatch; +import io.weaviate.client.v1.data.model.WeaviateObject; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -13,8 +14,6 @@ import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; import lombok.ToString; import lombok.experimental.FieldDefaults; @@ -51,12 +50,14 @@ private static class Properties { List booleanArrayProperties; List objectProperties; List objectArrayProperties; + List singleTargetRefProps; + List multiTargetRefProps; } private static WeaviateProtoBatch.BatchObject.Properties buildProperties(Map properties) { WeaviateProtoBatch.BatchObject.Properties.Builder builder = WeaviateProtoBatch.BatchObject.Properties.newBuilder(); - Properties props = extractProperties(properties); + Properties props = extractProperties(properties, true); builder.setNonRefProperties(Struct.newBuilder().putAllFields(props.nonRefProperties).build()); props.numberArrayProperties.forEach(builder::addNumberArrayProperties); props.intArrayProperties.forEach(builder::addIntArrayProperties); @@ -64,11 +65,13 @@ private static WeaviateProtoBatch.BatchObject.Properties buildProperties(Map properties) { + private static Properties extractProperties(Map properties, boolean rootLevel) { Map nonRefProperties = new HashMap<>(); List numberArrayProperties = new ArrayList<>(); List intArrayProperties = new ArrayList<>(); @@ -76,6 +79,8 @@ private static Properties extractProperties(Map properties) { List booleanArrayProperties = new ArrayList<>(); List objectProperties = new ArrayList<>(); List objectArrayProperties = new ArrayList<>(); + List singleTargetRefProps = new ArrayList<>(); + List multiTargetRefProps = new ArrayList<>(); // extract properties for (Map.Entry e : properties.entrySet()) { String propName = e.getKey(); @@ -146,7 +151,7 @@ private static Properties extractProperties(Map properties) { continue; } if (propValue instanceof Map) { - Properties extractedProperties = extractProperties((Map) propValue); + Properties extractedProperties = extractProperties((Map) propValue, false); WeaviateProtoBase.ObjectPropertiesValue.Builder objectPropertiesValue = WeaviateProtoBase.ObjectPropertiesValue.newBuilder(); objectPropertiesValue.setNonRefProperties(Struct.newBuilder().putAllFields(extractedProperties.nonRefProperties).build()); extractedProperties.numberArrayProperties.forEach(objectPropertiesValue::addNumberArrayProperties); @@ -163,30 +168,90 @@ private static Properties extractProperties(Map properties) { continue; } if (propValue instanceof List) { - List objectPropertiesValues = new ArrayList<>(); - for (Object propValueObject : (List) propValue) { - if (propValueObject instanceof Map) { - Properties extractedProperties = extractProperties((Map) propValueObject); - WeaviateProtoBase.ObjectPropertiesValue.Builder objectPropertiesValue = WeaviateProtoBase.ObjectPropertiesValue.newBuilder(); - objectPropertiesValue.setNonRefProperties(Struct.newBuilder().putAllFields(extractedProperties.nonRefProperties).build()); - extractedProperties.numberArrayProperties.forEach(objectPropertiesValue::addNumberArrayProperties); - extractedProperties.intArrayProperties.forEach(objectPropertiesValue::addIntArrayProperties); - extractedProperties.textArrayProperties.forEach(objectPropertiesValue::addTextArrayProperties); - extractedProperties.booleanArrayProperties.forEach(objectPropertiesValue::addBooleanArrayProperties); - extractedProperties.objectProperties.forEach(objectPropertiesValue::addObjectProperties); - extractedProperties.objectArrayProperties.forEach(objectPropertiesValue::addObjectArrayProperties); - - objectPropertiesValues.add(objectPropertiesValue.build()); + if (isCrossReference((List) propValue, rootLevel)) { + // it's a cross reference + List beacons = extractBeacons((List) propValue); + List crossReferences = beacons.stream() + .map(CrossReference::fromBeacon) + .collect(Collectors.toList()); + + Map> crefs = new HashMap<>(); + for (CrossReference cref : crossReferences) { + List uuids = crefs.get(cref.getClassName()); + if (uuids == null) { + uuids = new ArrayList<>(); + } + uuids.add(cref.getTargetID()); + crefs.put(cref.getClassName(), uuids); } - } - WeaviateProtoBase.ObjectArrayProperties objectArrayProps = WeaviateProtoBase.ObjectArrayProperties.newBuilder() - .setPropName(propName).addAllValues(objectPropertiesValues).build(); + if (crefs.size() == 1) { + for (Map.Entry> crefEntry : crefs.entrySet()) { + WeaviateProtoBatch.BatchObject.SingleTargetRefProps singleTargetCrossRefs = WeaviateProtoBatch.BatchObject.SingleTargetRefProps.newBuilder() + .setPropName(propName).addAllUuids(crefEntry.getValue()).build(); + singleTargetRefProps.add(singleTargetCrossRefs); + } + } + if (crefs.size() > 1) { + for (Map.Entry> crefEntry : crefs.entrySet()) { + WeaviateProtoBatch.BatchObject.MultiTargetRefProps multiTargetCrossRefs = WeaviateProtoBatch.BatchObject.MultiTargetRefProps.newBuilder() + .setPropName(propName).addAllUuids(crefEntry.getValue()).setTargetCollection(crefEntry.getKey()).build(); + multiTargetRefProps.add(multiTargetCrossRefs); + } + } + } else { + // it's an object + List objectPropertiesValues = new ArrayList<>(); + for (Object propValueObject : (List) propValue) { + if (propValueObject instanceof Map) { + Properties extractedProperties = extractProperties((Map) propValueObject, false); + WeaviateProtoBase.ObjectPropertiesValue.Builder objectPropertiesValue = WeaviateProtoBase.ObjectPropertiesValue.newBuilder(); + objectPropertiesValue.setNonRefProperties(Struct.newBuilder().putAllFields(extractedProperties.nonRefProperties).build()); + extractedProperties.numberArrayProperties.forEach(objectPropertiesValue::addNumberArrayProperties); + extractedProperties.intArrayProperties.forEach(objectPropertiesValue::addIntArrayProperties); + extractedProperties.textArrayProperties.forEach(objectPropertiesValue::addTextArrayProperties); + extractedProperties.booleanArrayProperties.forEach(objectPropertiesValue::addBooleanArrayProperties); + extractedProperties.objectProperties.forEach(objectPropertiesValue::addObjectProperties); + extractedProperties.objectArrayProperties.forEach(objectPropertiesValue::addObjectArrayProperties); + + objectPropertiesValues.add(objectPropertiesValue.build()); + } + } - objectArrayProperties.add(objectArrayProps); + WeaviateProtoBase.ObjectArrayProperties objectArrayProps = WeaviateProtoBase.ObjectArrayProperties.newBuilder() + .setPropName(propName).addAllValues(objectPropertiesValues).build(); + + objectArrayProperties.add(objectArrayProps); + } } } return new Properties(nonRefProperties, numberArrayProperties, intArrayProperties, textArrayProperties, - booleanArrayProperties, objectProperties, objectArrayProperties); + booleanArrayProperties, objectProperties, objectArrayProperties, singleTargetRefProps, multiTargetRefProps); + } + + private static boolean isCrossReference(List propValue, boolean rootLevel) { + if (rootLevel) { + for (Object element : propValue) { + if (element instanceof Map) { + Map valueMap = ((Map) element); + if (valueMap.size() > 1 || (valueMap.size() == 1 && (valueMap.get("beacon") == null || !(valueMap.get("beacon") instanceof String)))) { + return false; + } + } + } + return true; + } + return false; + } + + private static List extractBeacons(List propValue) { + List beacons = new ArrayList<>(); + for (Object element : propValue) { + if (element instanceof Map) { + Map valueMap = ((Map) element); + beacons.add((String) valueMap.get("beacon")); + } + } + return beacons; } } diff --git a/src/test/java/io/weaviate/client/base/util/CrossReferenceTest.java b/src/test/java/io/weaviate/client/base/util/CrossReferenceTest.java new file mode 100644 index 00000000..d51403d3 --- /dev/null +++ b/src/test/java/io/weaviate/client/base/util/CrossReferenceTest.java @@ -0,0 +1,47 @@ +package io.weaviate.client.base.util; + +import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; + +public class CrossReferenceTest { + + @Test + public void testParseBeaconWithClass() { + // given + String beacon = "weaviate://localhost/RefClass/f81bfe5e-16ba-4615-a516-46c2ae2e5a80"; + // when + CrossReference crossRef = CrossReference.fromBeacon(beacon); + // then + assertThat(crossRef).isNotNull().satisfies(cf -> { + assertThat(cf.isLocal()).isTrue(); + assertThat(cf.getPeerName()).isEqualTo("localhost"); + assertThat(cf.getClassName()).isEqualTo("RefClass"); + assertThat(cf.getTargetID()).isEqualTo("f81bfe5e-16ba-4615-a516-46c2ae2e5a80"); + }); + } + + @Test + public void testParseBeaconWithoutClass() { + // given + String beacon = "weaviate://localhost/f81bfe5e-16ba-4615-a516-46c2ae2e5a80"; + // when + CrossReference crossRef = CrossReference.fromBeacon(beacon); + // then + assertThat(crossRef).isNotNull().satisfies(cf -> { + assertThat(cf.isLocal()).isTrue(); + assertThat(cf.getPeerName()).isEqualTo("localhost"); + assertThat(cf.getClassName()).isEqualTo(""); + assertThat(cf.getTargetID()).isEqualTo("f81bfe5e-16ba-4615-a516-46c2ae2e5a80"); + }); + } + + @Test + public void testParseBeaconEmpty() { + // given + String beacon = ""; + // when + CrossReference crossRef = CrossReference.fromBeacon(beacon); + // then + assertThat(crossRef).isNull(); + } +} diff --git a/src/test/java/io/weaviate/integration/client/WeaviateTestGenerics.java b/src/test/java/io/weaviate/integration/client/WeaviateTestGenerics.java index 6f432b99..dcd128b0 100644 --- a/src/test/java/io/weaviate/integration/client/WeaviateTestGenerics.java +++ b/src/test/java/io/weaviate/integration/client/WeaviateTestGenerics.java @@ -33,6 +33,7 @@ import java.util.function.Supplier; import java.util.stream.IntStream; +import java.util.stream.Stream; import org.apache.commons.lang3.time.DateFormatUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.ARRAY; @@ -773,12 +774,24 @@ public void cleanupWeaviate(WeaviateClient client) { public static class AllPropertiesSchema { public String REF_CLASS = "RefClass"; + public String REF_CLASS_CATEGORY_PROPERTY = "category"; + public String REF_CLASS_CATEGORY_PROPERTY_TYPE = DataType.TEXT; + public String REF_CLASS2 = "RefClass2"; + public String REF_CLASS2_CATEGORY_PROPERTY = REF_CLASS_CATEGORY_PROPERTY; + public String REF_CLASS2_CATEGORY_PROPERTY_TYPE = REF_CLASS_CATEGORY_PROPERTY_TYPE; public String CLASS_NAME = "AllProperties"; - - public void createSchemaWithRefClass(WeaviateClient client) { - createClass(client); - createRefClass(client); - } + public String HAS_REF_PROP = "hasRefProp"; + public String HAS_REF_PROP2 = "hasRefProp2"; + + public String REF_ID1 = "a0000000-0000-0000-0000-000000000001"; + public String REF_ID2 = "a0000000-0000-0000-0000-000000000002"; + public String REF_ID3 = "a0000000-0000-0000-0000-000000000003"; + public String[] REF_IDS = new String[] { + REF_ID1, REF_ID2, REF_ID3 + }; + public String[] REF2_IDS = new String[] { + REF_ID1, REF_ID2, REF_ID3 + }; private void createClass(WeaviateClient client) { Result createResult = client.schema().classCreator() @@ -861,6 +874,26 @@ public List properties() { ); } + public List propertiesWithCrossReference() { + Property hasRefProperty = Property.builder() + .name(HAS_REF_PROP) + .dataType(Collections.singletonList(REF_CLASS)) + .build(); + List props = new ArrayList<>(properties()); + props.add(hasRefProperty); + return props; + } + + public List propertiesWithMultiCrossReference() { + Property hasRefProperty = Property.builder() + .name(HAS_REF_PROP2) + .dataType(Arrays.asList(REF_CLASS, REF_CLASS2)) + .build(); + List props = new ArrayList<>(propertiesWithCrossReference()); + props.add(hasRefProperty); + return props; + } + public List propertiesWithNestedObject() { Property objectProperty = Property.builder() .name("objectProperty") @@ -872,8 +905,7 @@ public List propertiesWithNestedObject() { .build() )) .build(); - List props = new ArrayList<>(); - props.addAll(properties()); + List props = new ArrayList<>(properties()); props.add(objectProperty); return props; } @@ -889,25 +921,65 @@ public List propertiesWithNestedObjectAndNestedArrayObject() { .build() )) .build(); - List props = new ArrayList<>(); - props.addAll(propertiesWithNestedObject()); + List props = new ArrayList<>(propertiesWithNestedObject()); props.add(objectArrayProperty); return props; } - private void createRefClass(WeaviateClient client) { - WeaviateClass jeopardyClass = WeaviateClass.builder() - .className(REF_CLASS) - .properties(Arrays.asList( + public List propertiesWithCrossReferenceWithNestedProperties() { + Property hasRefProperty = Property.builder() + .name(HAS_REF_PROP) + .dataType(Collections.singletonList(REF_CLASS)) + .build(); + List props = new ArrayList<>(propertiesWithNestedObjectAndNestedArrayObject()); + props.add(hasRefProperty); + return props; + } + + public List propertiesWithMultiCrossReferenceWithNestedProperties() { + Property hasRefProperty2 = Property.builder() + .name(HAS_REF_PROP2) + .dataType(Arrays.asList(REF_CLASS, REF_CLASS2)) + .build(); + List props = new ArrayList<>(propertiesWithCrossReferenceWithNestedProperties()); + props.add(hasRefProperty2); + return props; + } + + public void createRefClassesWithObjects(WeaviateClient client) { + createRefClasses(client); + createRefClassObjects(client, REF_CLASS, REF_CLASS_CATEGORY_PROPERTY); + createRefClassObjects(client, REF_CLASS2, REF_CLASS2_CATEGORY_PROPERTY); + } + + public void deleteRefClasses(WeaviateClient client) { + // clean up + Stream.of(REF_CLASS, REF_CLASS2).forEach(className -> { + Result delete = client.schema().classDeleter().withClassName(className).run(); + assertThat(delete).isNotNull() + .returns(false, Result::hasErrors) + .extracting(Result::getResult).isEqualTo(Boolean.TRUE); + }); + } + + private void createRefClasses(WeaviateClient client) { + createRefClasses(client, REF_CLASS, REF_CLASS_CATEGORY_PROPERTY, REF_CLASS_CATEGORY_PROPERTY_TYPE); + createRefClasses(client, REF_CLASS2, REF_CLASS2_CATEGORY_PROPERTY, REF_CLASS2_CATEGORY_PROPERTY_TYPE); + } + + private void createRefClasses(WeaviateClient client, String className, String propertyName, String propertyType) { + WeaviateClass refClass = WeaviateClass.builder() + .className(className) + .properties(Collections.singletonList( Property.builder() - .name("category") - .dataType(Arrays.asList(DataType.TEXT)) + .name(propertyName) + .dataType(Collections.singletonList(propertyType)) .build() )) .build(); Result result = client.schema().classCreator() - .withClass(jeopardyClass) + .withClass(refClass) .run(); assertThat(result).isNotNull() @@ -917,6 +989,33 @@ private void createRefClass(WeaviateClient client) { .returns(true, Result::getResult); } + private void createRefClassObjects(WeaviateClient client, String className, String propertyName) { + String[] refIds = REF_IDS; + String[] categories = new String[]{ + "science-fiction", "fantasy", "novel", + }; + + WeaviateObject[] objects = IntStream.range(0, refIds.length).mapToObj(i -> { + Map props = new HashMap<>(); + props.put(propertyName, categories[i]); + + return WeaviateObject.builder() + .className(className) + .id(refIds[i]) + .properties(props) + .build(); + } + ).toArray(WeaviateObject[]::new); + + Result result = client.batch().objectsBatcher() + .withObjects(objects) + .run(); + assertThat(result).isNotNull() + .returns(false, Result::hasErrors) + .extracting(Result::getResult).asInstanceOf(ARRAY) + .hasSize(objects.length); + } + public WeaviateObject[] objects() { String id1 = "00000000-0000-0000-0000-000000000001"; String id2 = "00000000-0000-0000-0000-000000000002"; @@ -1023,6 +1122,44 @@ public WeaviateObject[] objects() { return objects; } + private final List> createBeacon(String className, String id) { + Map refProperty = new HashMap<>(); + refProperty.put("beacon", String.format("weaviate://localhost/%s/%s", className, id)); + return Collections.singletonList(refProperty); + } + + private final List> createMultiRefBeacon(String className, String id, String className2, String id2) { + Map refProperty = new HashMap<>(); + refProperty.put("beacon", String.format("weaviate://localhost/%s/%s", className, id)); + Map refProperty2 = new HashMap<>(); + refProperty2.put("beacon", String.format("weaviate://localhost/%s/%s", className2, id2)); + return Arrays.asList(refProperty, refProperty2); + } + + private WeaviateObject[] objectsWithCrossReferences(WeaviateObject[] objects) { + IntStream.range(0, objects.length) + .forEach(i -> { + objects[i].getProperties().put(HAS_REF_PROP, createBeacon(REF_CLASS, REF_IDS[0])); + }); + return objects; + } + + private WeaviateObject[] objectsWithMultiCrossReferences(WeaviateObject[] objects) { + IntStream.range(0, objects.length) + .forEach(i -> { + objects[i].getProperties().put(HAS_REF_PROP2, createMultiRefBeacon(REF_CLASS, REF_IDS[1], REF_CLASS2, REF2_IDS[2])); + }); + return objects; + } + + public WeaviateObject[] objectsWithCrossReferences() { + return objectsWithCrossReferences(objects()); + } + + public WeaviateObject[] objectsWithMultiCrossReferences() { + return objectsWithMultiCrossReferences(objectsWithCrossReferences()); + } + public WeaviateObject[] objectsWithNestedObject() { try { File jsonFile = new File("src/test/resources/json/nested-one-object.json"); @@ -1043,7 +1180,7 @@ public WeaviateObject[] objectsWithNestedObjectAndNestedArrayObject() { File jsonFile = new File("src/test/resources/json/nested-array-object.json"); InputStreamReader reader = new InputStreamReader(Files.newInputStream(jsonFile.toPath())); final Object nestedArrayObject = new Gson().fromJson(reader, Object.class); - WeaviateObject[] objects = objects(); + WeaviateObject[] objects = objectsWithNestedObject(); Arrays.stream(objects).forEach(obj -> { obj.getProperties().put("objectArrayProperty", nestedArrayObject); }); @@ -1052,6 +1189,14 @@ public WeaviateObject[] objectsWithNestedObjectAndNestedArrayObject() { throw new RuntimeException(e); } } + + public WeaviateObject[] objectsWithCrossReferencesWithNestedProperties() { + return objectsWithCrossReferences(objectsWithNestedObjectAndNestedArrayObject()); + } + + public WeaviateObject[] objectsWithMultiCrossReferencesWithNestedProperties() { + return objectsWithMultiCrossReferences(objectsWithCrossReferencesWithNestedProperties()); + } } public DocumentPassageSchema documentPassageSchema() { diff --git a/src/test/java/io/weaviate/integration/client/WeaviateVersion.java b/src/test/java/io/weaviate/integration/client/WeaviateVersion.java index 4fa6ea3f..6fede9c2 100644 --- a/src/test/java/io/weaviate/integration/client/WeaviateVersion.java +++ b/src/test/java/io/weaviate/integration/client/WeaviateVersion.java @@ -3,9 +3,9 @@ public class WeaviateVersion { // to be set according to weaviate docker image - public static final String EXPECTED_WEAVIATE_VERSION = "1.22.0-rc.0"; + public static final String EXPECTED_WEAVIATE_VERSION = "1.22.3"; // to be set according to weaviate docker image - public static final String EXPECTED_WEAVIATE_GIT_HASH = "77dcea7"; + public static final String EXPECTED_WEAVIATE_GIT_HASH = "17502f2"; private WeaviateVersion() {} } diff --git a/src/test/java/io/weaviate/integration/client/batch/ClientBatchGrpcCreateTest.java b/src/test/java/io/weaviate/integration/client/batch/ClientBatchGrpcCreateTest.java index 591fa6ad..7904de48 100644 --- a/src/test/java/io/weaviate/integration/client/batch/ClientBatchGrpcCreateTest.java +++ b/src/test/java/io/weaviate/integration/client/batch/ClientBatchGrpcCreateTest.java @@ -29,8 +29,8 @@ public class ClientBatchGrpcCreateTest { @ClassRule public static ComposeContainer compose = new ComposeContainer( new File("src/test/resources/docker-compose-test.yaml") - ).withExposedService("weaviate-1", 8080, Wait.forHttp("/v1/.well-known/ready").forStatusCode(200)) - .withExposedService("weaviate-1", 50051, Wait.forListeningPort()) + ).withExposedService("weaviate-1", 8080, Wait.forListeningPorts(8080)) + .withExposedService("weaviate-1", 50051, Wait.forListeningPorts(50051)) .withTailChildContainers(true); @Before @@ -41,6 +41,7 @@ public void before() { grpcPort = compose.getServicePort("weaviate-1", 50051); } + @Test public void shouldCreateBatchUsingGRPC() { testCreateBatch(true); @@ -56,6 +57,26 @@ public void shouldCreateBatchWithNestedObjectAndNestedArrayObjectUsingGRPC() { testCreateBatchWithNestedAndNestArrayObject(true); } + @Test + public void shouldCreateBatchWithCrossReferencesUsingGRPC() { + testCreateBatchWithReferenceWithoutNested(true); + } + + @Test + public void shouldCreateBatchWithMultiCrossReferencesUsingGRPC() { + testCreateBatchWithMultiReferenceWithoutNested(true); + } + + @Test + public void shouldCreateBatchWithCrossReferencesWithNestedPropertiesUsingGRPC() { + testCreateBatchWithReferenceWithNested(true); + } + + @Test + public void shouldCreateBatchWithMultiCrossReferencesWithNestedPropertiesUsingGRPC() { + testCreateBatchWithMultiReferenceWithNested(true); + } + @Test public void shouldCreateBatchUsingRest() { testCreateBatch(false); @@ -71,35 +92,117 @@ public void shouldCreateBatchWithNestedObjectAndNestedArrayObjectUsingRest() { testCreateBatchWithNestedAndNestArrayObject(false); } + @Test + public void shouldCreateBatchWithCrossReferencesUsingRest() { + testCreateBatchWithReferenceWithoutNested(false); + } + + @Test + public void shouldCreateBatchWithMultiCrossReferencesUsingRest() { + testCreateBatchWithMultiReferenceWithoutNested(false); + } + + @Test + public void shouldCreateBatchWithCrossReferencesWithNestedPropertiesUsingRest() { + testCreateBatchWithReferenceWithNested(false); + } + + @Test + public void shouldCreateBatchWithMultiCrossReferencesWithNestedPropertiesUsingRest() { + testCreateBatchWithMultiReferenceWithNested(false); + } + + private void testCreateBatchWithReferenceWithoutNested(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); + WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); + // create ref class and populate objects + testData.createRefClassesWithObjects(client); + // create all properties class + String className = testData.CLASS_NAME; + List properties = testData.propertiesWithCrossReference(); + WeaviateObject[] objects = testData.objectsWithCrossReferences(); + testCreateBatch(client, className, properties, objects); + // delete ref class + testData.deleteRefClasses(client); + } + + private void testCreateBatchWithMultiReferenceWithoutNested(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); + WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); + // create ref class and populate objects + testData.createRefClassesWithObjects(client); + // create all properties class + String className = testData.CLASS_NAME; + List properties = testData.propertiesWithMultiCrossReference(); + WeaviateObject[] objects = testData.objectsWithMultiCrossReferences(); + testCreateBatch(client, className, properties, objects); + // delete ref class + testData.deleteRefClasses(client); + } + + private void testCreateBatchWithReferenceWithNested(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); + WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); + // create ref class and populate objects + testData.createRefClassesWithObjects(client); + // create all properties class + String className = testData.CLASS_NAME; + List properties = testData.propertiesWithCrossReferenceWithNestedProperties(); + WeaviateObject[] objects = testData.objectsWithCrossReferencesWithNestedProperties(); + testCreateBatch(client, className, properties, objects); + // delete ref class + testData.deleteRefClasses(client); + } + + private void testCreateBatchWithMultiReferenceWithNested(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); + WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); + // create ref class and populate objects + testData.createRefClassesWithObjects(client); + // create all properties class + String className = testData.CLASS_NAME; + List properties = testData.propertiesWithMultiCrossReferenceWithNestedProperties(); + WeaviateObject[] objects = testData.objectsWithMultiCrossReferencesWithNestedProperties(); + testCreateBatch(client, className, properties, objects); + // delete ref class + testData.deleteRefClasses(client); + } + private void testCreateBatch(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); String className = testData.CLASS_NAME; List properties = testData.properties(); WeaviateObject[] objects = testData.objects(); - testCreateBatch(useGRPC, className, properties, objects); + testCreateBatch(client, className, properties, objects); } private void testCreateBatchWithNested(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); String className = testData.CLASS_NAME; List properties = testData.propertiesWithNestedObject(); WeaviateObject[] objects = testData.objectsWithNestedObject(); - testCreateBatch(useGRPC, className, properties, objects); + testCreateBatch(client, className, properties, objects); } private void testCreateBatchWithNestedAndNestArrayObject(Boolean useGRPC) { + WeaviateClient client = createClient(useGRPC); WeaviateTestGenerics.AllPropertiesSchema testData = new WeaviateTestGenerics.AllPropertiesSchema(); String className = testData.CLASS_NAME; List properties = testData.propertiesWithNestedObjectAndNestedArrayObject(); WeaviateObject[] objects = testData.objectsWithNestedObjectAndNestedArrayObject(); - testCreateBatch(useGRPC, className, properties, objects); + testCreateBatch(client, className, properties, objects); } - private void testCreateBatch(Boolean useGRPC, String className, List properties, WeaviateObject[] objects) { + private WeaviateClient createClient(Boolean useGRPC) { Config config = new Config("http", host + ":" + port); config.setUseGRPC(useGRPC); config.setGrpcAddress(grpcHost + ":" + grpcPort); - WeaviateClient client = new WeaviateClient(config); + return new WeaviateClient(config); + } + + private void testCreateBatch(WeaviateClient client, String className, List properties, WeaviateObject[] objects) { // create schema Result createResult = client.schema().classCreator() .withClass(WeaviateClass.builder() @@ -132,6 +235,9 @@ private void testCreateBatch(Boolean useGRPC, String className, List p assertThat(o.getId()).isEqualTo(obj.getId()); assertThat(o.getProperties()).isNotNull() .extracting(Map::size).isEqualTo(obj.getProperties().size()); + obj.getProperties().keySet().stream().forEach(propName -> { + assertThat(o.getProperties().get(propName)).isNotNull(); + }); }); } // clean up diff --git a/src/test/resources/docker-compose-azure.yaml b/src/test/resources/docker-compose-azure.yaml index 49746d22..af64a7f6 100644 --- a/src/test/resources/docker-compose-azure.yaml +++ b/src/test/resources/docker-compose-azure.yaml @@ -10,7 +10,7 @@ services: - --scheme - http - --write-timeout=600s - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: PERSISTENCE_DATA_PATH: '/var/lib/weaviate' diff --git a/src/test/resources/docker-compose-cluster.yaml b/src/test/resources/docker-compose-cluster.yaml index 23181444..02fb1fea 100644 --- a/src/test/resources/docker-compose-cluster.yaml +++ b/src/test/resources/docker-compose-cluster.yaml @@ -10,7 +10,7 @@ services: - --scheme - http - --write-timeout=600s - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: LOG_LEVEL: 'debug' @@ -41,7 +41,7 @@ services: - '8088' - --scheme - http - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: LOG_LEVEL: 'debug' diff --git a/src/test/resources/docker-compose-okta-cc.yaml b/src/test/resources/docker-compose-okta-cc.yaml index c318427e..79a329fb 100644 --- a/src/test/resources/docker-compose-okta-cc.yaml +++ b/src/test/resources/docker-compose-okta-cc.yaml @@ -10,7 +10,7 @@ services: - --scheme - http - --write-timeout=600s - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: PERSISTENCE_DATA_PATH: '/var/lib/weaviate' diff --git a/src/test/resources/docker-compose-okta-users.yaml b/src/test/resources/docker-compose-okta-users.yaml index 53e1f0f2..d6434c07 100644 --- a/src/test/resources/docker-compose-okta-users.yaml +++ b/src/test/resources/docker-compose-okta-users.yaml @@ -10,7 +10,7 @@ services: - --scheme - http - --write-timeout=600s - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: PERSISTENCE_DATA_PATH: '/var/lib/weaviate' diff --git a/src/test/resources/docker-compose-proxy.yaml b/src/test/resources/docker-compose-proxy.yaml index d00273b0..9fb7fb61 100644 --- a/src/test/resources/docker-compose-proxy.yaml +++ b/src/test/resources/docker-compose-proxy.yaml @@ -9,7 +9,7 @@ services: - '8080' - --scheme - http - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: LOG_LEVEL: "debug" diff --git a/src/test/resources/docker-compose-test.yaml b/src/test/resources/docker-compose-test.yaml index f9fd7bb4..deb03558 100644 --- a/src/test/resources/docker-compose-test.yaml +++ b/src/test/resources/docker-compose-test.yaml @@ -9,7 +9,7 @@ services: - '8080' - --scheme - http - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 links: - "contextionary:contextionary" restart: on-failure:0 diff --git a/src/test/resources/docker-compose-wcs.yaml b/src/test/resources/docker-compose-wcs.yaml index 5a2e5060..f2ac2163 100644 --- a/src/test/resources/docker-compose-wcs.yaml +++ b/src/test/resources/docker-compose-wcs.yaml @@ -10,7 +10,7 @@ services: - --scheme - http - --write-timeout=600s - image: semitechnologies/weaviate:preview-fix-grpc-batch-api-autoschema-77dcea7 + image: semitechnologies/weaviate:1.22.3 restart: on-failure:0 environment: PERSISTENCE_DATA_PATH: '/var/lib/weaviate'