diff --git a/src/main/java/io/weaviate/client/v1/schema/model/DataType.java b/src/main/java/io/weaviate/client/v1/schema/model/DataType.java index 08625f5f..d8a7c6b2 100644 --- a/src/main/java/io/weaviate/client/v1/schema/model/DataType.java +++ b/src/main/java/io/weaviate/client/v1/schema/model/DataType.java @@ -16,6 +16,8 @@ public interface DataType { String GEO_COORDINATES = "geoCoordinates"; String PHONE_NUMBER = "phoneNumber"; String UUID = "uuid"; + String OBJECT = "object"; + /** * As of Weaviate v1.19 'string[]' is deprecated and replaced by 'text[]'.
* See data types @@ -28,4 +30,5 @@ public interface DataType { String BOOLEAN_ARRAY = "boolean[]"; String DATE_ARRAY = "date[]"; String UUID_ARRAY = "uuid[]"; + String OBJECT_ARRAY = "object[]"; } diff --git a/src/main/java/io/weaviate/client/v1/schema/model/Property.java b/src/main/java/io/weaviate/client/v1/schema/model/Property.java index 409cc391..f287613b 100644 --- a/src/main/java/io/weaviate/client/v1/schema/model/Property.java +++ b/src/main/java/io/weaviate/client/v1/schema/model/Property.java @@ -28,4 +28,21 @@ public class Property { Boolean indexFilterable; Boolean indexSearchable; Object moduleConfig; + List nestedProperties; + + + @Getter + @Builder + @ToString + @EqualsAndHashCode + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + public static class NestedProperty { + String name; + List dataType; + String description; + String tokenization; + Boolean indexFilterable; + Boolean indexSearchable; + List nestedProperties; + } } diff --git a/src/test/java/io/weaviate/integration/client/WeaviateVersion.java b/src/test/java/io/weaviate/integration/client/WeaviateVersion.java index ae679bf3..09ea62a5 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.21.0"; + public static final String EXPECTED_WEAVIATE_VERSION = "1.21.5"; // to be set according to weaviate docker image - public static final String EXPECTED_WEAVIATE_GIT_HASH = "8172acb"; + public static final String EXPECTED_WEAVIATE_GIT_HASH = "8a40c6b"; private WeaviateVersion() {} } diff --git a/src/test/java/io/weaviate/integration/client/schema/ClientSchemaDefaultsAndMigrationTest.java b/src/test/java/io/weaviate/integration/client/schema/ClientSchemaDefaultsAndMigrationTest.java index ea86d95a..cffe9d53 100644 --- a/src/test/java/io/weaviate/integration/client/schema/ClientSchemaDefaultsAndMigrationTest.java +++ b/src/test/java/io/weaviate/integration/client/schema/ClientSchemaDefaultsAndMigrationTest.java @@ -448,179 +448,179 @@ public static Object[][] provideInvalidForDataTypeAndIndexing() { new Object[]{ DataType.TEXT, Boolean.FALSE, null, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, null, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.FALSE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.TRUE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, null, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, null, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.FALSE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.FALSE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.TRUE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.TEXT, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, null, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, null, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.FALSE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.FALSE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.FALSE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.TRUE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, null, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, null, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.FALSE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.FALSE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.TRUE, null, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE, - "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`.", + "`indexInverted` is deprecated and can not be set together with `indexFilterable` or `indexSearchable`", }, new Object[]{ DataType.INT, null, null, Boolean.TRUE, - "`indexSearchable` is allowed only for text/text[] data types. For other data types set false or leave empty", + "`indexSearchable` is not allowed for other than text/text[] data types", }, new Object[]{ DataType.INT, null, Boolean.FALSE, Boolean.TRUE, - "`indexSearchable` is allowed only for text/text[] data types. For other data types set false or leave empty", + "`indexSearchable` is not allowed for other than text/text[] data types", }, new Object[]{ DataType.INT, null, Boolean.TRUE, Boolean.TRUE, - "`indexSearchable` is allowed only for text/text[] data types. For other data types set false or leave empty", + "`indexSearchable` is not allowed for other than text/text[] data types", }, }; } diff --git a/src/test/java/io/weaviate/integration/client/schema/ClientSchemaTest.java b/src/test/java/io/weaviate/integration/client/schema/ClientSchemaTest.java index 6ddf3c27..67a12db2 100644 --- a/src/test/java/io/weaviate/integration/client/schema/ClientSchemaTest.java +++ b/src/test/java/io/weaviate/integration/client/schema/ClientSchemaTest.java @@ -4,6 +4,8 @@ import io.weaviate.client.WeaviateClient; import io.weaviate.client.base.Result; import io.weaviate.client.base.WeaviateErrorMessage; +import io.weaviate.client.v1.batch.model.ObjectGetResponse; +import io.weaviate.client.v1.data.model.WeaviateObject; import io.weaviate.client.v1.misc.model.BM25Config; import io.weaviate.client.v1.misc.model.DistanceType; import io.weaviate.client.v1.misc.model.InvertedIndexConfig; @@ -46,6 +48,7 @@ public class ClientSchemaTest { private WeaviateClient client; + private final NestedObjectsUtils utils = new NestedObjectsUtils(); @ClassRule public static DockerComposeContainer compose = new DockerComposeContainer( @@ -995,4 +998,359 @@ private void assertPropertyEquals(String expectedName, String expectedDataType, assertTrue(property.getDataType().size() > 0); assertEquals(expectedDataType, property.getDataType().get(0)); } + + @Test + public void shouldAddObjectsWithNestedProperties_EntireSchema() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassEntireSchema(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding object 1 + WeaviateObject object1 = utils.createObject(client, utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), object1); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding object 2 + WeaviateObject object2 = utils.createObject(client, utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), object2); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_PartialSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema1(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema did not change after adding object 1 + WeaviateObject object1 = utils.createObject(client, utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), object1); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 2 + WeaviateObject object2 = utils.createObject(client, utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), object2); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_PartialSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema2(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema did not change after adding object 2 + WeaviateObject object2 = utils.createObject(client, utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), object2); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 1 + WeaviateObject object1 = utils.createObject(client, utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), object1); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_NoSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding object 1 + WeaviateObject object1 = utils.createObject(client, utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), object1); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 2 + WeaviateObject object2 = utils.createObject(client, utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), object2); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_NoSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding object 2 + WeaviateObject object2 = utils.createObject(client, utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), object2); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 1 + WeaviateObject object1 = utils.createObject(client, utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), object1); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_EntireSchema() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassEntireSchema(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding objects + ObjectGetResponse[] objects = utils.batchObjects(client, utils.nestedObject1(className), utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), objects[0]); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), objects[1]); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_PartialSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema1(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding objects + ObjectGetResponse[] objects = utils.batchObjects(client, utils.nestedObject1(className), utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), objects[0]); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), objects[1]); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_PartialSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema2(className); + utils.createClass(client, wvtClass); + + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding objects + ObjectGetResponse[] objects = utils.batchObjects(client, utils.nestedObject1(className), utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), objects[0]); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), objects[1]); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_NoSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding objects + ObjectGetResponse[] objects = utils.batchObjects(client, utils.nestedObject1(className), utils.nestedObject2(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), objects[0]); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), objects[1]); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_NoSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding objects + ObjectGetResponse[] objects = utils.batchObjects(client, utils.nestedObject2(className), utils.nestedObject1(className)); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject2(className), objects[0]); + utils.assertThatObjectsAreSimilar(utils.expectedNestedObject1(className), objects[1]); + schemaClass = utils.getClass(client, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } } diff --git a/src/test/java/io/weaviate/integration/client/schema/ClusterSchemaTest.java b/src/test/java/io/weaviate/integration/client/schema/ClusterSchemaTest.java index 1e69fdda..5e850f84 100644 --- a/src/test/java/io/weaviate/integration/client/schema/ClusterSchemaTest.java +++ b/src/test/java/io/weaviate/integration/client/schema/ClusterSchemaTest.java @@ -5,7 +5,10 @@ import io.weaviate.client.base.Result; import io.weaviate.client.base.WeaviateError; import io.weaviate.client.base.WeaviateErrorMessage; +import io.weaviate.client.v1.batch.model.ObjectGetResponse; +import io.weaviate.client.v1.data.model.WeaviateObject; import io.weaviate.client.v1.misc.model.ReplicationConfig; +import io.weaviate.client.v1.schema.model.DataType; import io.weaviate.client.v1.schema.model.WeaviateClass; import org.apache.http.HttpStatus; import org.junit.After; @@ -16,31 +19,41 @@ import org.testcontainers.containers.wait.strategy.Wait; import java.io.File; +import java.util.HashMap; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.STRING; public class ClusterSchemaTest { - private WeaviateClient client; + private WeaviateClient client1; + private WeaviateClient client2; + private final NestedObjectsUtils utils = new NestedObjectsUtils(); @ClassRule - public static DockerComposeContainer compose = new DockerComposeContainer( + public static DockerComposeContainer compose = new DockerComposeContainer<>( new File("src/test/resources/docker-compose-cluster.yaml") - ).withExposedService("weaviate-node-1_1", 8087, Wait.forHttp("/v1/.well-known/ready").forStatusCode(200)); + ) + .withExposedService("weaviate-node-1_1", 8087, Wait.forHttp("/v1/.well-known/ready").forStatusCode(200)) + .withExposedService("weaviate-node-2_1", 8088, Wait.forHttp("/v1/.well-known/ready").forStatusCode(200)); @Before public void before() { - String host = compose.getServiceHost("weaviate-node-1_1", 8087); - Integer port = compose.getServicePort("weaviate-node-1_1", 8087); - Config config = new Config("http", host + ":" + port); + String host1 = compose.getServiceHost("weaviate-node-1_1", 8087); + Integer port1 = compose.getServicePort("weaviate-node-1_1", 8087); + Config config1 = new Config("http", host1 + ":" + port1); + client1 = new WeaviateClient(config1); - client = new WeaviateClient(config); + String host2 = compose.getServiceHost("weaviate-node-2_1", 8088); + Integer port2 = compose.getServicePort("weaviate-node-2_1", 8088); + Config config2 = new Config("http", host2 + ":" + port2); + client2 = new WeaviateClient(config2); } @After public void after() { - Result deleted = client.schema().allDeleter().run(); + Result deleted = client1.schema().allDeleter().run(); assertThat(deleted.hasErrors()).isFalse(); } @@ -58,13 +71,13 @@ public void shouldCreateClassWithImplicitReplicationFactor() { .build(); // when - Result createStatus = client.schema().classCreator().withClass(clazz).run(); + Result createStatus = client1.schema().classCreator().withClass(clazz).run(); assertThat(createStatus).isNotNull() .returns(false, Result::hasErrors) .returns(true, Result::getResult); // then - Result classResult = client.schema().classGetter().withClassName(className).run(); + Result classResult = client1.schema().classGetter().withClassName(className).run(); assertThat(classResult).isNotNull() .returns(false, Result::hasErrors) .extracting(Result::getResult).isNotNull() @@ -89,13 +102,13 @@ public void shouldCreateClassWithExplicitReplicationFactor() { .build(); // when - Result createStatus = client.schema().classCreator().withClass(clazz).run(); + Result createStatus = client1.schema().classCreator().withClass(clazz).run(); assertThat(createStatus).isNotNull() .returns(false, Result::hasErrors) .returns(true, Result::getResult); // then - Result classResult = client.schema().classGetter().withClassName(className).run(); + Result classResult = client1.schema().classGetter().withClassName(className).run(); assertThat(classResult).isNotNull() .returns(false, Result::hasErrors) .extracting(Result::getResult).isNotNull() @@ -120,7 +133,7 @@ public void shouldNotCreateClassWithTooHighFactor() { .build(); // when - Result createStatus = client.schema().classCreator().withClass(clazz).run(); + Result createStatus = client1.schema().classCreator().withClass(clazz).run(); assertThat(createStatus).isNotNull() .returns(true, Result::hasErrors) .extracting(Result::getError) @@ -129,5 +142,370 @@ public void shouldNotCreateClassWithTooHighFactor() { .first() .extracting(m -> ((WeaviateErrorMessage) m).getMessage()).asInstanceOf(STRING) .contains("not enough replicas"); + }@Test + public void shouldAddObjectsWithNestedProperties_EntireSchema() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassEntireSchema(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding object 1 + utils.createObject(client1, utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding object 2 + utils.createObject(client1, utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_PartialSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema1(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema did not change after adding object 1 + utils.createObject(client1, utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 2 + utils.createObject(client1, utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_PartialSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema2(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema did not change after adding object 2 + utils.createObject(client1, utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 1 + utils.createObject(client1, utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_NoSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding object 1 + utils.createObject(client1, utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 2 + utils.createObject(client1, utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldAddObjectsWithNestedProperties_NoSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding object 2 + utils.createObject(client1, utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding object 1 + utils.createObject(client1, utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_EntireSchema() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassEntireSchema(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + + // schema did not change after adding objects + utils.batchObjects(client1, utils.nestedObject1(className), utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_PartialSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.INT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema1(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding objects + utils.batchObjects(client1, utils.nestedObject1(className), utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_PartialSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedPropsStep1 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + Map expectedPropsStep2 = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + WeaviateClass wvtClass = utils.nestedClassPartialSchema2(className); + utils.createClass(client1, wvtClass); + + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep1, schemaClass); + + // schema changed after adding objects + utils.batchObjects(client1, utils.nestedObject1(className), utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedPropsStep2, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_NoSchema1() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding objects + utils.batchObjects(client1, utils.nestedObject1(className), utils.nestedObject2(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + } + + @Test + public void shouldBatchObjectsWithNestedProperties_NoSchema2() { + WeaviateClass schemaClass; + String className = "ClassWithObjectProperty"; + Map expectedProps = new HashMap() {{ + put("name", DataType.TEXT); + put("objectProperty", DataType.OBJECT); + put("objectProperty.nestedInt", DataType.NUMBER); // autoschema determines type as number + put("objectProperty.nestedNumber", DataType.NUMBER); + put("objectProperty.nestedText", DataType.TEXT); + put("objectProperty.nestedObjects", DataType.OBJECT_ARRAY); + put("objectProperty.nestedObjects.nestedBoolLvl2", DataType.BOOLEAN); + put("objectProperty.nestedObjects.nestedDateLvl2", DataType.DATE); + put("objectProperty.nestedObjects.nestedNumbersLvl2", DataType.NUMBER_ARRAY); + }}; + + // schema created after adding objects + utils.batchObjects(client1, utils.nestedObject2(className), utils.nestedObject1(className)); + schemaClass = utils.getClass(client1, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); + schemaClass = utils.getClass(client2, className); + utils.assertThatSchemaPropertiesHaveDataTypes(expectedProps, schemaClass); } } diff --git a/src/test/java/io/weaviate/integration/client/schema/NestedObjectsUtils.java b/src/test/java/io/weaviate/integration/client/schema/NestedObjectsUtils.java new file mode 100644 index 00000000..448c27c0 --- /dev/null +++ b/src/test/java/io/weaviate/integration/client/schema/NestedObjectsUtils.java @@ -0,0 +1,363 @@ +package io.weaviate.integration.client.schema; + +import io.weaviate.client.WeaviateClient; +import io.weaviate.client.base.Result; +import io.weaviate.client.v1.batch.model.ObjectGetResponse; +import io.weaviate.client.v1.batch.model.ObjectGetResponseStatus; +import io.weaviate.client.v1.batch.model.ObjectsGetResponseAO2Result; +import io.weaviate.client.v1.data.model.WeaviateObject; +import io.weaviate.client.v1.schema.model.DataType; +import io.weaviate.client.v1.schema.model.Property; +import io.weaviate.client.v1.schema.model.Schema; +import io.weaviate.client.v1.schema.model.WeaviateClass; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.InstanceOfAssertFactories.ARRAY; + +class NestedObjectsUtils { + + WeaviateClass nestedClassEntireSchema(String className) { + return WeaviateClass.builder() + .className(className) + .properties(Arrays.asList( + Property.builder() + .name("name") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.builder() + .name("objectProperty") + .dataType(Arrays.asList(DataType.OBJECT)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedInt") + .dataType(Arrays.asList(DataType.INT)) + .build(), + Property.NestedProperty.builder() + .name("nestedNumber") + .dataType(Arrays.asList(DataType.NUMBER)) + .build(), + Property.NestedProperty.builder() + .name("nestedText") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.NestedProperty.builder() + .name("nestedObjects") + .dataType(Arrays.asList(DataType.OBJECT_ARRAY)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedBoolLvl2") + .dataType(Arrays.asList(DataType.BOOLEAN)) + .build(), + Property.NestedProperty.builder() + .name("nestedDateLvl2") + .dataType(Arrays.asList(DataType.DATE)) + .build(), + Property.NestedProperty.builder() + .name("nestedNumbersLvl2") + .dataType(Arrays.asList(DataType.NUMBER_ARRAY)) + .build() + )) + .build() + )) + .build() + )) + .build(); + } + + WeaviateClass nestedClassPartialSchema1(String className) { + return WeaviateClass.builder() + .className(className) + .properties(Arrays.asList( + Property.builder() + .name("name") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.builder() + .name("objectProperty") + .dataType(Arrays.asList(DataType.OBJECT)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedInt") + .dataType(Arrays.asList(DataType.INT)) + .build(), + Property.NestedProperty.builder() + .name("nestedText") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.NestedProperty.builder() + .name("nestedObjects") + .dataType(Arrays.asList(DataType.OBJECT_ARRAY)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedBoolLvl2") + .dataType(Arrays.asList(DataType.BOOLEAN)) + .build(), + Property.NestedProperty.builder() + .name("nestedNumbersLvl2") + .dataType(Arrays.asList(DataType.NUMBER_ARRAY)) + .build() + )) + .build() + )) + .build() + )) + .build(); + } + + WeaviateClass nestedClassPartialSchema2(String className) { + return WeaviateClass.builder() + .className(className) + .properties(Arrays.asList( + Property.builder() + .name("name") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.builder() + .name("objectProperty") + .dataType(Arrays.asList(DataType.OBJECT)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedNumber") + .dataType(Arrays.asList(DataType.NUMBER)) + .build(), + Property.NestedProperty.builder() + .name("nestedText") + .dataType(Arrays.asList(DataType.TEXT)) + .build(), + Property.NestedProperty.builder() + .name("nestedObjects") + .dataType(Arrays.asList(DataType.OBJECT_ARRAY)) + .nestedProperties(Arrays.asList( + Property.NestedProperty.builder() + .name("nestedDateLvl2") + .dataType(Arrays.asList(DataType.DATE)) + .build(), + Property.NestedProperty.builder() + .name("nestedNumbersLvl2") + .dataType(Arrays.asList(DataType.NUMBER_ARRAY)) + .build() + )) + .build() + )) + .build() + )) + .build(); + } + + WeaviateObject nestedObject1(String className) { + Map nestedPropsLvl2 = new HashMap<>(); + nestedPropsLvl2.put("nestedBoolLvl2", false); + nestedPropsLvl2.put("nestedNumbersLvl2", Arrays.asList(1.1, 11.11)); + + Map nestedPropsLvl1 = new HashMap<>(); + nestedPropsLvl1.put("nestedInt", 111); + nestedPropsLvl1.put("nestedText", "some text 1"); + nestedPropsLvl1.put("nestedObjects", Arrays.asList(nestedPropsLvl2)); + + Map props = new HashMap<>(); + props.put("name", "object1"); + props.put("objectProperty", nestedPropsLvl1); + + return WeaviateObject.builder() + .className(className) + .id("040f2b60-b1e8-4b4d-ba0d-14cedb5144ab") + .properties(props) + .build(); + } + + WeaviateObject expectedNestedObject1(String className) { + // overwrite ints with doubles, as they are unmarshalled as that type + WeaviateObject o = nestedObject1(className); + Map objectProperty = (Map) o.getProperties().get("objectProperty"); + objectProperty.put("nestedInt", 111.0); + + return o; + } + + WeaviateObject nestedObject2(String className) { + Map nestedPropsLvl2 = new HashMap<>(); + nestedPropsLvl2.put("nestedDateLvl2", "2022-01-01T00:00:00+02:00"); + nestedPropsLvl2.put("nestedNumbersLvl2", Arrays.asList(2.2, 22.22)); + + Map nestedPropsLvl1 = new HashMap<>(); + nestedPropsLvl1.put("nestedNumber", 222); + nestedPropsLvl1.put("nestedText", "some text 2"); + nestedPropsLvl1.put("nestedObjects", Arrays.asList(nestedPropsLvl2)); + + Map props = new HashMap<>(); + props.put("name", "object2"); + props.put("objectProperty", nestedPropsLvl1); + + return WeaviateObject.builder() + .className(className) + .id("d3ca0fc9-d392-4253-8f2a-0bce51efff80") + .properties(props) + .build(); + } + + WeaviateObject expectedNestedObject2(String className) { + // overwrite ints with doubles, as they are unmarshalled as that type + WeaviateObject o = nestedObject2(className); + Map objectProperty = (Map) o.getProperties().get("objectProperty"); + objectProperty.put("nestedNumber", 222.0); + + return o; + } + + void createClass(WeaviateClient client, WeaviateClass wvtClass) { + Result createClass = client.schema().classCreator() + .withClass(wvtClass) + .run(); + + assertThat(createClass).isNotNull() + .returns(false, Result::hasErrors) + .returns(true, Result::getResult); + } + + WeaviateClass getClass(WeaviateClient client, String className) { + Result getSchema = client.schema().getter().run(); + assertThat(getSchema).isNotNull() + .returns(false, Result::hasErrors) + .extracting(Result::getResult).isNotNull(); + + Optional optionalClass = getSchema.getResult().getClasses().stream() + .filter(c -> className.equals(c.getClassName())) + .findFirst(); + assertThat(optionalClass).isPresent(); + + return optionalClass.get(); + } + + WeaviateObject createObject(WeaviateClient client, WeaviateObject object) { + Result createObject = client.data().creator() + .withID(object.getId()) + .withClassName(object.getClassName()) + .withProperties(object.getProperties()) + .run(); + + assertThat(createObject).isNotNull() + .returns(false, Result::hasErrors) + .extracting(Result::getResult).isNotNull(); + + return createObject.getResult(); + } + + ObjectGetResponse[] batchObjects(WeaviateClient client, WeaviateObject... objects) { + Result batchObjects = client.batch().objectsBatcher() + .withObjects(objects) + .run(); + + assertThat(batchObjects).isNotNull() + .returns(false, Result::hasErrors) + .extracting(Result::getResult).asInstanceOf(ARRAY) + .hasSize(objects.length); + + Arrays.stream(batchObjects.getResult()).forEach(obj -> { + assertThat(obj).isNotNull() + .extracting(ObjectGetResponse::getResult).isNotNull() + .returns(ObjectGetResponseStatus.SUCCESS, ObjectsGetResponseAO2Result::getStatus) + .returns(null, ObjectsGetResponseAO2Result::getErrors); + }); + + return batchObjects.getResult(); + } + + void assertThatSchemaPropertiesHaveDataTypes(Map expectedProps, WeaviateClass schemaClass) { + Map>> propNumbers = expectedProps.entrySet().stream().collect(Collectors.groupingBy(entry -> { + String[] parts = StringUtils.split(entry.getKey(), "."); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length - 1; i++) { + if (i != 0) { + sb.append("."); + } + sb.append(parts[i]); + } + return sb.toString(); + })); + + propNumbers.forEach((propName, props) -> { + if ("".equals(propName)) { + assertThat(schemaClass.getProperties()).isNotNull() + .hasSize(props.size()); + } else { + String[] parts = StringUtils.split(propName, "."); + Optional optionalProp = schemaClass.getProperties().stream() + .filter(p -> parts[0].equals(p.getName())) + .findFirst(); + assertThat(optionalProp).isPresent(); + + List nestedProps = optionalProp.get().getNestedProperties(); + + for (int i = 1; i < parts.length; i++) { + int index = i; + Optional optionalNestedProp = nestedProps.stream() + .filter(np -> parts[index].equals(np.getName())) + .findFirst(); + assertThat(optionalNestedProp).isPresent(); + nestedProps = optionalNestedProp.get().getNestedProperties(); + } + + assertThat(nestedProps).hasSize(props.size()); + } + }); + + expectedProps.forEach((name, dataType) -> { + String[] parts = StringUtils.split(name, "."); + if (parts.length > 0) { + Optional optionalProp = schemaClass.getProperties().stream() + .filter(p -> parts[0].equals(p.getName())) + .findFirst(); + + assertThat(optionalProp).isPresent(); + Property property = optionalProp.get(); + + if (parts.length == 1) { + assertThat(property) + .extracting(Property::getDataType).asList() + .first().isEqualTo(dataType); + } else { + Property.NestedProperty nestedProp = null; + + List nestedProps = property.getNestedProperties(); + for (int i = 1; i < parts.length; i++) { + int index = i; + assertThat(nestedProps).isNotNull(); + Optional optionalNestedProp = nestedProps.stream() + .filter(np -> parts[index].equals(np.getName())) + .findFirst(); + assertThat(optionalNestedProp).isPresent(); + nestedProp = optionalNestedProp.get(); + nestedProps = nestedProp.getNestedProperties(); + } + + assertThat(nestedProp).isNotNull() + .extracting(Property.NestedProperty::getDataType).asList() + .first().isEqualTo(dataType); + } + } + }); + } + + void assertThatObjectsAreSimilar(WeaviateObject expectedObject, WeaviateObject object) { + assertThat(object).isNotNull() + .returns(expectedObject.getId(), WeaviateObject::getId) + .returns(expectedObject.getClassName(), WeaviateObject::getClassName) + .extracting(WeaviateObject::getProperties) + .isEqualTo(expectedObject.getProperties()); + } + void assertThatObjectsAreSimilar(WeaviateObject expectedObject, ObjectGetResponse object) { + assertThat(object).isNotNull() + .returns(expectedObject.getId(), ObjectGetResponse::getId) + .returns(expectedObject.getClassName(), ObjectGetResponse::getClassName) + .extracting(ObjectGetResponse::getProperties) + .isEqualTo(expectedObject.getProperties()); + } +} diff --git a/src/test/resources/docker-compose-azure.yaml b/src/test/resources/docker-compose-azure.yaml index 8820688c..9a9530a3 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 642765e0..f57fc8a1 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b restart: on-failure:0 environment: LOG_LEVEL: 'debug' @@ -41,7 +41,7 @@ services: - '8088' - --scheme - http - image: semitechnologies/weaviate:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 f81b4a21..e3bd1d2f 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 b7304138..3a3f84d3 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 cbe6dc62..35ca7171 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 8dec0f7d..e1dc288e 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b 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 ffeb22dc..d05b8d07 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:1.21.0 + image: semitechnologies/weaviate:preview-adds-support-for-object-object-data-types-8a40c6b restart: on-failure:0 environment: PERSISTENCE_DATA_PATH: '/var/lib/weaviate'