diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0edba690c..df10d2afc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,7 @@ on: - release paths-ignore: - "README.md" + - "CHANGELOG.md" jobs: build_linux: diff --git a/.gitignore b/.gitignore index 6c74eda30..0eb467263 100644 --- a/.gitignore +++ b/.gitignore @@ -451,6 +451,7 @@ captures/ test.log /build !no2-old.db +!no2-v3.db .diffblue infer-out secring.gpg \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d248a2f15..b721d5a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## Release 4.3.0 + +### New Changes + +- Nitrite now supports JPMS. It is now modular and can be used in Java 9 or above. +- Version upgrade for several dependencies +- Repository type validation can be disabled in `NitriteBuilder` as a fix for #966 + +### Issue Fixes + +- Fix for #935 +- Fix for #948 +- Fix for #961 +- Fix for #966 +- Fix for #977 +- Fix for #990 + ## Release 4.2.2 - Mar 5, 2024 ### Issue Fixes diff --git a/nitrite-bom/pom.xml b/nitrite-bom/pom.xml index 37666b8aa..2adcda87a 100644 --- a/nitrite-bom/pom.xml +++ b/nitrite-bom/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-bom diff --git a/nitrite-jackson-mapper/pom.xml b/nitrite-jackson-mapper/pom.xml index 8b22dccea..3828db19f 100644 --- a/nitrite-jackson-mapper/pom.xml +++ b/nitrite-jackson-mapper/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-jackson-mapper @@ -144,6 +144,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2.jackson + + + + diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/common/mapper/JacksonMapperTest.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/common/mapper/JacksonMapperTest.java index 4bf36c02d..87efabe06 100644 --- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/common/mapper/JacksonMapperTest.java +++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/common/mapper/JacksonMapperTest.java @@ -17,183 +17,24 @@ package org.dizitart.no2.common.mapper; -import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.cfg.ContextAttributes; -import com.fasterxml.jackson.databind.introspect.VisibilityChecker; -import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; -import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.BinaryNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import org.dizitart.no2.NitriteConfig; -import org.dizitart.no2.common.mapper.modules.NitriteIdModule; import org.dizitart.no2.exceptions.ObjectMappingException; import org.junit.Test; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; import static org.junit.Assert.*; public class JacksonMapperTest { - @Test - public void testConstructor() { - ObjectMapper objectMapper = (new JacksonMapper()).getObjectMapper(); - PolymorphicTypeValidator polymorphicTypeValidator = objectMapper.getPolymorphicTypeValidator(); - assertTrue(polymorphicTypeValidator instanceof LaissezFaireSubTypeValidator); - VisibilityChecker visibilityChecker = objectMapper.getVisibilityChecker(); - assertTrue(visibilityChecker instanceof VisibilityChecker.Std); - assertNull(objectMapper.getPropertyNamingStrategy()); - assertTrue(objectMapper - .getDeserializationContext() instanceof com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl); - assertSame(objectMapper.getFactory(), objectMapper.getJsonFactory()); - assertTrue(objectMapper.getSerializerFactory() instanceof com.fasterxml.jackson.databind.ser.BeanSerializerFactory); - assertTrue(objectMapper - .getSerializerProvider() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue(objectMapper - .getSerializerProviderInstance() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue( - objectMapper.getSubtypeResolver() instanceof com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver); - DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig(); - assertTrue(deserializationConfig - .getAnnotationIntrospector() instanceof com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector); - assertNull(deserializationConfig.getActiveView()); - assertNull(deserializationConfig.getHandlerInstantiator()); - assertSame(visibilityChecker, deserializationConfig.getDefaultVisibilityChecker()); - assertTrue(deserializationConfig - .getClassIntrospector() instanceof com.fasterxml.jackson.databind.introspect.BasicClassIntrospector); - DateFormat expectedDateFormat = objectMapper.getDateFormat(); - assertSame(expectedDateFormat, deserializationConfig.getDateFormat()); - assertNull(deserializationConfig.getFullRootName()); - JsonNodeFactory expectedNodeFactory = objectMapper.getNodeFactory(); - assertSame(expectedNodeFactory, deserializationConfig.getNodeFactory()); - assertSame(polymorphicTypeValidator, deserializationConfig.getPolymorphicTypeValidator()); - assertNull(deserializationConfig.getDefaultMergeable()); - assertEquals(237020288, deserializationConfig.getDeserializationFeatures()); - assertTrue(deserializationConfig.getAttributes() instanceof ContextAttributes.Impl); - } - - @Test - public void testConstructor2() { - NitriteIdModule nitriteIdModule = new NitriteIdModule(); - NitriteIdModule nitriteIdModule1 = new NitriteIdModule(); - JacksonMapper jacksonMapper = new JacksonMapper(); - jacksonMapper.registerJacksonModule(nitriteIdModule); - jacksonMapper.registerJacksonModule(nitriteIdModule1); - jacksonMapper.registerJacksonModule(new NitriteIdModule()); - ObjectMapper objectMapper = jacksonMapper.getObjectMapper(); - PolymorphicTypeValidator polymorphicTypeValidator = objectMapper.getPolymorphicTypeValidator(); - assertTrue(polymorphicTypeValidator instanceof LaissezFaireSubTypeValidator); - VisibilityChecker visibilityChecker = objectMapper.getVisibilityChecker(); - assertTrue(visibilityChecker instanceof VisibilityChecker.Std); - assertNull(objectMapper.getPropertyNamingStrategy()); - assertTrue(objectMapper - .getDeserializationContext() instanceof com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl); - assertSame(objectMapper.getFactory(), objectMapper.getJsonFactory()); - assertTrue(objectMapper.getSerializerFactory() instanceof com.fasterxml.jackson.databind.ser.BeanSerializerFactory); - assertTrue(objectMapper - .getSerializerProvider() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue(objectMapper - .getSerializerProviderInstance() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue( - objectMapper.getSubtypeResolver() instanceof com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver); - DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig(); - assertTrue(deserializationConfig - .getAnnotationIntrospector() instanceof com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector); - assertNull(deserializationConfig.getActiveView()); - assertNull(deserializationConfig.getHandlerInstantiator()); - assertSame(visibilityChecker, deserializationConfig.getDefaultVisibilityChecker()); - assertTrue(deserializationConfig - .getClassIntrospector() instanceof com.fasterxml.jackson.databind.introspect.BasicClassIntrospector); - DateFormat expectedDateFormat = objectMapper.getDateFormat(); - assertSame(expectedDateFormat, deserializationConfig.getDateFormat()); - assertNull(deserializationConfig.getFullRootName()); - JsonNodeFactory expectedNodeFactory = objectMapper.getNodeFactory(); - assertSame(expectedNodeFactory, deserializationConfig.getNodeFactory()); - assertSame(polymorphicTypeValidator, deserializationConfig.getPolymorphicTypeValidator()); - assertNull(deserializationConfig.getDefaultMergeable()); - assertEquals(237020288, deserializationConfig.getDeserializationFeatures()); - assertTrue(deserializationConfig.getAttributes() instanceof ContextAttributes.Impl); - } - - @Test - public void testConstructor3() { - JacksonMapper jacksonMapper = new JacksonMapper(); - jacksonMapper.registerJacksonModule(new NitriteIdModule()); - ObjectMapper objectMapper = jacksonMapper.getObjectMapper(); - PolymorphicTypeValidator polymorphicTypeValidator = objectMapper.getPolymorphicTypeValidator(); - assertTrue(polymorphicTypeValidator instanceof LaissezFaireSubTypeValidator); - VisibilityChecker visibilityChecker = objectMapper.getVisibilityChecker(); - assertTrue(visibilityChecker instanceof VisibilityChecker.Std); - assertNull(objectMapper.getPropertyNamingStrategy()); - assertTrue(objectMapper - .getDeserializationContext() instanceof com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl); - assertSame(objectMapper.getFactory(), objectMapper.getJsonFactory()); - assertTrue(objectMapper.getSerializerFactory() instanceof com.fasterxml.jackson.databind.ser.BeanSerializerFactory); - assertTrue(objectMapper - .getSerializerProvider() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue(objectMapper - .getSerializerProviderInstance() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue( - objectMapper.getSubtypeResolver() instanceof com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver); - DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig(); - assertTrue(deserializationConfig - .getAnnotationIntrospector() instanceof com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector); - assertNull(deserializationConfig.getActiveView()); - assertNull(deserializationConfig.getHandlerInstantiator()); - assertSame(visibilityChecker, deserializationConfig.getDefaultVisibilityChecker()); - assertTrue(deserializationConfig - .getClassIntrospector() instanceof com.fasterxml.jackson.databind.introspect.BasicClassIntrospector); - DateFormat expectedDateFormat = objectMapper.getDateFormat(); - assertSame(expectedDateFormat, deserializationConfig.getDateFormat()); - assertNull(deserializationConfig.getFullRootName()); - JsonNodeFactory expectedNodeFactory = objectMapper.getNodeFactory(); - assertSame(expectedNodeFactory, deserializationConfig.getNodeFactory()); - assertSame(polymorphicTypeValidator, deserializationConfig.getPolymorphicTypeValidator()); - assertNull(deserializationConfig.getDefaultMergeable()); - assertEquals(237020288, deserializationConfig.getDeserializationFeatures()); - assertTrue(deserializationConfig.getAttributes() instanceof ContextAttributes.Impl); - } - @Test public void testGetObjectMapper() { ObjectMapper actualCreateObjectMapperResult = (new JacksonMapper()).getObjectMapper(); - PolymorphicTypeValidator polymorphicTypeValidator = actualCreateObjectMapperResult.getPolymorphicTypeValidator(); - assertTrue(polymorphicTypeValidator instanceof LaissezFaireSubTypeValidator); - VisibilityChecker visibilityChecker = actualCreateObjectMapperResult.getVisibilityChecker(); - assertTrue(visibilityChecker instanceof VisibilityChecker.Std); - assertNull(actualCreateObjectMapperResult.getPropertyNamingStrategy()); - assertTrue(actualCreateObjectMapperResult - .getDeserializationContext() instanceof com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl); - assertSame(actualCreateObjectMapperResult.getFactory(), actualCreateObjectMapperResult.getJsonFactory()); - assertTrue(actualCreateObjectMapperResult - .getSerializerFactory() instanceof com.fasterxml.jackson.databind.ser.BeanSerializerFactory); - assertTrue(actualCreateObjectMapperResult - .getSerializerProvider() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue(actualCreateObjectMapperResult - .getSerializerProviderInstance() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - assertTrue(actualCreateObjectMapperResult - .getSubtypeResolver() instanceof com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver); - DeserializationConfig deserializationConfig = actualCreateObjectMapperResult.getDeserializationConfig(); - assertTrue(deserializationConfig.getAttributes() instanceof ContextAttributes.Impl); - assertTrue(deserializationConfig - .getAnnotationIntrospector() instanceof com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector); - assertNull(deserializationConfig.getActiveView()); - assertEquals(237020288, deserializationConfig.getDeserializationFeatures()); - DateFormat expectedDateFormat = actualCreateObjectMapperResult.getDateFormat(); - assertSame(expectedDateFormat, deserializationConfig.getDateFormat()); - assertNull(deserializationConfig.getDefaultMergeable()); - assertSame(visibilityChecker, deserializationConfig.getDefaultVisibilityChecker()); - assertNull(deserializationConfig.getHandlerInstantiator()); - JsonNodeFactory expectedNodeFactory = actualCreateObjectMapperResult.getNodeFactory(); - assertSame(expectedNodeFactory, deserializationConfig.getNodeFactory()); - assertSame(polymorphicTypeValidator, deserializationConfig.getPolymorphicTypeValidator()); - assertTrue(deserializationConfig - .getClassIntrospector() instanceof com.fasterxml.jackson.databind.introspect.BasicClassIntrospector); - assertNull(deserializationConfig.getFullRootName()); - assertNull(deserializationConfig.getProblemHandlers()); + assertNotNull(actualCreateObjectMapperResult); } @Test diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/NitriteTest.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/NitriteTest.java index 01043be8a..5790fa388 100644 --- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/NitriteTest.java +++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/NitriteTest.java @@ -33,7 +33,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -264,9 +263,7 @@ public void testNoUniqueAndTextIndex() { @Data @NoArgsConstructor @AllArgsConstructor - @Indices({ - @Index(fields = "synced", type = IndexType.NON_UNIQUE) - }) + @Index(fields = "synced", type = IndexType.NON_UNIQUE) public static class Receipt { @Id private String clientRef; @@ -283,21 +280,17 @@ public enum Status { public static class EmptyClass { } - @Indices({ - @Index(fields = "value", type = IndexType.FULL_TEXT), - @Index(fields = "value") - }) @Data @NoArgsConstructor @AllArgsConstructor + @Index(fields = "value", type = IndexType.FULL_TEXT) + @Index(fields = "value") public static class EntityUniqueFullText { private String value; } - @Indices({ - @Index(fields = "value", type = IndexType.FULL_TEXT), - @Index(fields = "value", type = IndexType.NON_UNIQUE) - }) + @Index(fields = "value", type = IndexType.FULL_TEXT) + @Index(fields = "value", type = IndexType.NON_UNIQUE) @Data @NoArgsConstructor @AllArgsConstructor diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java index 888a31550..c932c7d4d 100644 --- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java +++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java @@ -31,7 +31,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -113,11 +112,9 @@ public void testFindByEmbeddedField() { @ToString @EqualsAndHashCode - @Indices({ - @Index(fields = "joinDate", type = IndexType.NON_UNIQUE), - @Index(fields = "address", type = IndexType.FULL_TEXT), - @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) - }) + @Index(fields = "joinDate", type = IndexType.NON_UNIQUE) + @Index(fields = "address", type = IndexType.FULL_TEXT) + @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) public static class EmployeeForCustomSeparator implements Serializable { @Id @Getter diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java index e92fa2848..6aa3ab298 100644 --- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java +++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java @@ -29,7 +29,6 @@ import org.dizitart.no2.repository.Cursor; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -173,9 +172,7 @@ public void testUniversalFullTextIndexing() { } } - @Indices( - @Index(fields = "text", type = IndexType.FULL_TEXT) - ) + @Index(fields = "text", type = IndexType.FULL_TEXT) public static class TextData { public int id; public String text; diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/data/Company.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/data/Company.java index 3a6721f73..acf8c9311 100644 --- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/data/Company.java +++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/integration/repository/data/Company.java @@ -24,7 +24,6 @@ import lombok.ToString; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import java.io.Serializable; import java.util.Date; @@ -38,9 +37,7 @@ @Setter @ToString @EqualsAndHashCode -@Indices({ - @Index(fields = "companyName") -}) +@Index(fields = "companyName") public class Company implements Serializable { @Id(fieldName = "company_id") @JsonProperty("company_id") diff --git a/nitrite-mvstore-adapter/pom.xml b/nitrite-mvstore-adapter/pom.xml index f4bb929d0..4409d86c8 100644 --- a/nitrite-mvstore-adapter/pom.xml +++ b/nitrite-mvstore-adapter/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-mvstore-adapter @@ -182,6 +182,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2.mvstore + + + + diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/MVStoreUtils.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/MVStoreUtils.java index 93cd5f56a..2bd30c13e 100644 --- a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/MVStoreUtils.java +++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/MVStoreUtils.java @@ -17,18 +17,15 @@ package org.dizitart.no2.mvstore; import lombok.extern.slf4j.Slf4j; -import org.dizitart.no2.common.meta.Attributes; import org.dizitart.no2.exceptions.InvalidOperationException; import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.mvstore.compat.v1.UpgradeUtil; -import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStoreException; import java.io.File; +import java.util.Map; -import static org.dizitart.no2.common.Constants.META_MAP_NAME; -import static org.dizitart.no2.common.Constants.STORE_INFO; import static org.dizitart.no2.common.util.StringUtils.isNullOrEmpty; /** @@ -38,6 +35,10 @@ @Slf4j(topic = "nitrite-mvstore") @SuppressWarnings("ALL") class MVStoreUtils { + private static final String OLD_DATABASE_FORMAT = "Old database format detected."; + private static final String OLD_STORE_FORMAT = "The write format 1 is smaller than the supported format"; + private static final Integer OLD_DATABASE_FORMAT_VERSION = 29062024; + private MVStoreUtils() { } @@ -48,7 +49,10 @@ static MVStore openOrCreate(MVStoreConfig storeConfig) { File dbFile = !isNullOrEmpty(storeConfig.filePath()) ? new File(storeConfig.filePath()) : null; try { store = builder.open(); - testForMigration(store); + if (dbFile != null) { + // if the store is file based, test for migration + testForMigration(store); + } } catch (MVStoreException me) { if (me.getMessage().contains("file is locked")) { throw new NitriteIOException("Database is already opened in other process"); @@ -105,7 +109,7 @@ static MVStore openOrCreate(MVStoreConfig storeConfig) { } private static boolean isCompatibilityError(Exception e) { - return e.getMessage().contains("The write format 1 is smaller than the supported format"); + return e.getMessage().contains(OLD_DATABASE_FORMAT) || e.getMessage().contains(OLD_STORE_FORMAT); } private static MVStore.Builder createBuilder(MVStoreConfig mvStoreConfig) { @@ -210,22 +214,23 @@ private static void switchFiles(File newFile, File orgFile) { private static void testForMigration(MVStore store) { if (store != null) { - if (store.hasMap(STORE_INFO)) { - return; + Map storeHeader = store.getStoreHeader(); + if (storeHeader == null || storeHeader.isEmpty()) { + throw new MVStoreException(OLD_DATABASE_FORMAT_VERSION, OLD_DATABASE_FORMAT); } - MVStore.TxCounter txCounter = store.registerVersionUsage(); - MVMap metaMap = store.openMap(META_MAP_NAME); - try { - // fire one operation to trigger compatibility issue - // if no exception thrown, then the database is compatible - metaMap.remove("MigrationTest"); - } catch (IllegalStateException e) { - store.close(); - throw e; - } finally { - if (!store.isClosed()) { - store.deregisterVersionUsage(txCounter); + if (storeHeader.containsKey("format")) { + Object rawFormatValue = storeHeader.get("format"); + if (rawFormatValue instanceof Integer) { + int format = (int) rawFormatValue; + if (format < 3) { + throw new MVStoreException(OLD_DATABASE_FORMAT_VERSION, OLD_DATABASE_FORMAT); + } + } else { + int format = Integer.parseInt((String) storeHeader.get("format")); + if (format < 3) { + throw new MVStoreException(OLD_DATABASE_FORMAT_VERSION, OLD_DATABASE_FORMAT); + } } } } diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVStore.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVStore.java index 8834cc838..e4b80e627 100644 --- a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVStore.java +++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVStore.java @@ -17,7 +17,9 @@ package org.dizitart.no2.mvstore; +import lombok.extern.slf4j.Slf4j; import org.dizitart.no2.common.util.StringUtils; +import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.index.BoundingBox; import org.dizitart.no2.store.AbstractNitriteStore; import org.dizitart.no2.store.NitriteMap; @@ -26,15 +28,19 @@ import org.dizitart.no2.store.events.StoreEvents; import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; +import org.h2.mvstore.MVStoreException; import org.h2.mvstore.rtree.MVRTreeMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import static org.h2.mvstore.DataUtils.*; + /** * @since 1.0 * @author Anindya Chatterjee */ +@Slf4j public class NitriteMVStore extends AbstractNitriteStore { private MVStore mvStore; private final Map> nitriteMapRegistry; @@ -109,7 +115,7 @@ public NitriteMap openMap(String mapName, Class keyT return (NitriteMVMap) nitriteMapRegistry.get(mapName); } - MVMap mvMap = mvStore.openMap(mapName); + MVMap mvMap = openMVMap(mapName, null); NitriteMVMap nitriteMVMap = new NitriteMVMap<>(mvMap, this); nitriteMapRegistry.put(mapName, nitriteMVMap); return nitriteMVMap; @@ -131,7 +137,7 @@ public void closeRTree(String rTreeName) { @Override public void removeMap(String name) { - MVMap mvMap = mvStore.openMap(name); + MVMap mvMap = openMVMap(name, null); mvStore.removeMap(mvMap); getCatalog().remove(name); nitriteMapRegistry.remove(name); @@ -140,7 +146,7 @@ public void removeMap(String name) { @Override @SuppressWarnings({"rawtypes"}) public void removeRTree(String rTreeName) { - MVMap mvMap = mvStore.openMap(rTreeName, new MVRTreeMap.Builder<>()); + MVMap mvMap = openMVMap(rTreeName, new MVRTreeMap.Builder<>()); mvStore.removeMap(mvMap); getCatalog().remove(rTreeName); nitriteRTreeMapRegistry.remove(rTreeName); @@ -153,7 +159,7 @@ public NitriteRTree openRTree(Strin return (NitriteMVRTreeMap) nitriteRTreeMapRegistry.get(mapName); } - MVRTreeMap map = mvStore.openMap(mapName, new MVRTreeMap.Builder<>()); + MVRTreeMap map = (MVRTreeMap) openMVMap(mapName, new MVRTreeMap.Builder<>()); NitriteMVRTreeMap nitriteMVRTreeMap = new NitriteMVRTreeMap(map, this); nitriteRTreeMapRegistry.put(mapName, nitriteMVRTreeMap); return nitriteMVRTreeMap; @@ -171,4 +177,39 @@ private void initEventBus() { } } } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private MVMap openMVMap(String mapName, MVMap.MapBuilder builder) { + Exception exception = null; + try { + MVMap.MapBuilder mapBuilder = builder == null ? new MVMap.Builder<>() : builder; + long version = mvStore.getCurrentVersion(); + + while (version >= 0) { + try { + return mvStore.openMap(mapName, mapBuilder); + } catch (MVStoreException me) { + if (version == 0) { + throw me; + } + + log.warn("Error opening map {} with version {}, retrying with previous version", mapName, version, me); + if (me.getErrorCode() == ERROR_READING_FAILED || me.getErrorCode() == ERROR_WRITING_FAILED + || me.getErrorCode() == ERROR_FILE_CORRUPT || me.getErrorCode() == ERROR_SERIALIZATION + || me.getErrorCode() == ERROR_CHUNK_NOT_FOUND || me.getErrorCode() == ERROR_BLOCK_NOT_FOUND) { + // open map with earlier version + mvStore.rollbackTo(version - 1); + version = mvStore.getCurrentVersion(); + } else { + throw me; + } + exception = me; + } + } + } catch (Exception e) { + exception = e; + } + + throw new NitriteIOException("Unable to open map " + mapName, exception); + } } diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v1/UpgradeUtil.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v1/UpgradeUtil.java index 5099915a2..827ba3766 100644 --- a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v1/UpgradeUtil.java +++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v1/UpgradeUtil.java @@ -190,7 +190,12 @@ private static Document document(Compat.Document value) { Document document = Document.createDocument(); for (Map.Entry entry : value.entrySet()) { Object val = entry.getValue(); - Object migratedVal = migrateValue(val); + Object migratedVal; + if (DOC_ID.equals(entry.getKey())) { + migratedVal = String.valueOf(val); + } else { + migratedVal = migrateValue(val); + } document.put(entry.getKey(), migratedVal); } return document; diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteTest.java index 8fe84ef0c..1a3d26524 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteTest.java @@ -28,8 +28,8 @@ import org.dizitart.no2.common.SortOrder; import org.dizitart.no2.common.concurrent.ThreadPoolManager; import org.dizitart.no2.common.mapper.EntityConverter; -import org.dizitart.no2.common.mapper.SimpleNitriteMapper; import org.dizitart.no2.common.mapper.NitriteMapper; +import org.dizitart.no2.common.mapper.SimpleNitriteMapper; import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.exceptions.ValidationException; import org.dizitart.no2.index.IndexOptions; @@ -41,7 +41,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -437,6 +436,44 @@ public void testIssue193() throws InterruptedException { pool.shutdown(); } + @Test + public void testUpdateDocumentsFromVersion3() throws IOException { + if (Files.exists(Paths.get(System.getProperty("java.io.tmpdir") + File.separator + "no2-v3.db"))) { + Files.delete(Paths.get(System.getProperty("java.io.tmpdir") + File.separator + "no2-v3.db")); + } + + InputStream stream = ClassLoader.getSystemResourceAsStream("no2-v3.db"); + if (stream == null) { + stream = ClassLoader.getSystemClassLoader().getResourceAsStream("no2-v3.db"); + } + assert stream != null; + + Files.copy(stream, Paths.get(System.getProperty("java.io.tmpdir") + File.separator + "no2-v3.db")); + + String oldDbFile = System.getProperty("java.io.tmpdir") + File.separator + "no2-v3.db"; + Nitrite db = TestUtil.createDb(oldDbFile); + NitriteCollection testCollection = db.getCollection("test"); + Document document = testCollection.find().firstOrNull(); + document.put("name", "new-name"); + + boolean exception = false; + try { + testCollection.update(document); + } catch (Exception e) { + exception = true; + log.error("Error while updating document", e); + } + assertFalse(exception); + + db.close(); + + try { + Files.deleteIfExists(Paths.get(oldDbFile)); + } catch (IOException e) { + log.error("Error while deleting db", e); + } + } + @Test public void testReadCompatibility() throws IOException { // ******* Old DB Creation Code Start ********* @@ -532,7 +569,11 @@ public void testReadCompatibility() throws IOException { db.close(); - //TODO: CHeck reopen with repo. That should also fails too. + try { + Files.deleteIfExists(Paths.get(oldDbFile)); + } catch (IOException e) { + log.error("Error while deleting db", e); + } } @Test @@ -674,9 +715,7 @@ public CompatChild fromDocument(Document document, NitriteMapper nitriteMapper) @Data @NoArgsConstructor @AllArgsConstructor - @Indices({ - @Index(fields = "synced", type = IndexType.NON_UNIQUE) - }) + @Index(fields = "synced", type = IndexType.NON_UNIQUE) public static class Receipt { @Id private String clientRef; diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java index f185d2dd6..c4d3db29d 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java @@ -35,7 +35,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.*; import uk.co.jemos.podam.api.PodamFactory; import uk.co.jemos.podam.api.PodamFactoryImpl; @@ -371,11 +370,9 @@ public PerfTest fromDocument(Document document, NitriteMapper nitriteMapper) { } } - @Indices({ - @Index(fields = "firstName", type = IndexType.NON_UNIQUE), - @Index(fields = "age", type = IndexType.NON_UNIQUE), - @Index(fields = "text", type = IndexType.FULL_TEXT), - }) + @Index(fields = "firstName", type = IndexType.NON_UNIQUE) + @Index(fields = "age", type = IndexType.NON_UNIQUE) + @Index(fields = "text", type = IndexType.FULL_TEXT) private static class PerfTestIndexed extends PerfTest { public static class Converter implements EntityConverter { diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/BaseCollectionTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/BaseCollectionTest.java index 200d7c873..033a279ed 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/BaseCollectionTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/BaseCollectionTest.java @@ -64,7 +64,7 @@ public abstract class BaseCollectionTest { public Retry retry = new Retry(3); @Parameterized.Parameters(name = "InMemory = {0}, Secured = {1}, " + - "Compressed = {2}, AutoCommit = {3}, AutoCompact = {4}") + "Compressed = {2}, AutoCommit = {3}") public static Collection data() { return Arrays.asList(new Object[][]{ {false, false, false, false}, diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionCompoundIndexNegativeTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionCompoundIndexNegativeTest.java index 746fe397b..b9e627250 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionCompoundIndexNegativeTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionCompoundIndexNegativeTest.java @@ -57,7 +57,7 @@ public void testCreateUniqueMultiKeyIndexOnArray() { public void testCreateOnInvalidField() { insert(); // multiple null value will be created - collection.createIndex( "my-value", "lastName"); + collection.createIndex("my-value", "lastName"); } @Test(expected = IndexingException.class) diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java index 7dedc072f..4d7814e5b 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java @@ -822,4 +822,32 @@ public void testByIdFilter() { result = collection.find(or(byId(nitriteId), where("tag").eq(document.get("tag")))).firstOrNull(); assertEquals(document, result); } + + @Test + public void testByNonExistingId() { + Document doc1 = createDocument("age", 31).put("tag", "one"); + Document doc2 = createDocument("age", 32).put("tag", "two"); + Document doc3 = createDocument("age", 33).put("tag", "three"); + Document doc4 = createDocument("age", 34).put("tag", "four"); + Document doc5 = createDocument("age", 35).put("tag", "five"); + + NitriteCollection collection = db.getCollection("tag"); + collection.insert(doc1, doc2, doc3, doc4, doc5); + + NitriteId nitriteId = NitriteId.newId(); + Document result = collection.find(byId(nitriteId)).firstOrNull(); + assertNull(result); + + result = collection.find(and(byId(nitriteId), where("age").notEq(null))).firstOrNull(); + assertNull(result); + + result = collection.find(or(byId(nitriteId), where("tag").eq("one"))).firstOrNull(); + assertNotNull(result); + assertEquals(result.get("tag"), "one"); + + DocumentCursor cursor = collection.find(where("_id").eq(nitriteId.getIdValue())); + Iterator idIter = cursor.iterator(); + assertFalse(idIter.hasNext()); + assertEquals(cursor.size(), 0); + } } diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java index 72886734b..d25f6e917 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java @@ -21,21 +21,20 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import org.dizitart.no2.Nitrite; +import org.dizitart.no2.NitriteConfig; +import org.dizitart.no2.collection.Document; import org.dizitart.no2.common.mapper.EntityConverter; +import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.common.mapper.SimpleNitriteMapper; +import org.dizitart.no2.index.IndexType; import org.dizitart.no2.integration.Retry; import org.dizitart.no2.integration.repository.data.Company; import org.dizitart.no2.integration.repository.data.Note; -import org.dizitart.no2.Nitrite; -import org.dizitart.no2.NitriteConfig; -import org.dizitart.no2.collection.Document; -import org.dizitart.no2.index.IndexType; -import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.mvstore.MVStoreModule; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -123,11 +122,9 @@ public void testFindByEmbeddedField() { @ToString @EqualsAndHashCode - @Indices({ - @Index(fields = "joinDate", type = IndexType.NON_UNIQUE), - @Index(fields = "address", type = IndexType.FULL_TEXT), - @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) - }) + @Index(fields = "joinDate", type = IndexType.NON_UNIQUE) + @Index(fields = "address", type = IndexType.FULL_TEXT) + @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) public static class EmployeeForCustomSeparator implements Serializable { @Id @Getter diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java index b49ebde04..883797035 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java @@ -32,7 +32,6 @@ import org.dizitart.no2.repository.Cursor; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -179,9 +178,7 @@ public void testUniversalFullTextIndexing() { } } - @Indices( - @Index(fields = "text", type = IndexType.FULL_TEXT) - ) + @Index(fields = "text", type = IndexType.FULL_TEXT) public static class TextData { public Integer id; public String text; diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java index d720ceee4..86b927638 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java @@ -25,7 +25,6 @@ import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import java.io.Serializable; import java.util.Date; @@ -37,9 +36,7 @@ */ @Getter @EqualsAndHashCode -@Indices({ - @Index(fields = "companyName") -}) +@Index(fields = "companyName") public class Company implements Serializable { @Id(fieldName = "company_id") @Setter diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/MVStoreUtilsTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/MVStoreUtilsTest.java index 78f61ef9b..0873e21a7 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/MVStoreUtilsTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/MVStoreUtilsTest.java @@ -33,9 +33,9 @@ public void testOpenOrCreate() { assertEquals(0, actualOpenOrCreateResult.getUnsavedMemory()); assertEquals(0, actualOpenOrCreateResult.getStoreVersion()); assertEquals(0, actualOpenOrCreateResult.getRetentionTime()); - assertEquals(2, actualOpenOrCreateResult.getMetaMap().size()); + assertEquals(0, actualOpenOrCreateResult.getMetaMap().size()); assertEquals(Long.MAX_VALUE, actualOpenOrCreateResult.getMaxPageSize()); - assertEquals(1, actualOpenOrCreateResult.getMapNames().size()); + assertEquals(0, actualOpenOrCreateResult.getMapNames().size()); assertEquals(48, actualOpenOrCreateResult.getKeysPerPage()); assertEquals(0, actualOpenOrCreateResult.getAutoCommitMemory()); } @@ -50,9 +50,9 @@ public void testOpenOrCreate2() { assertEquals(0, actualOpenOrCreateResult.getUnsavedMemory()); assertEquals(0, actualOpenOrCreateResult.getStoreVersion()); assertEquals(0, actualOpenOrCreateResult.getRetentionTime()); - assertEquals(2, actualOpenOrCreateResult.getMetaMap().size()); + assertEquals(0, actualOpenOrCreateResult.getMetaMap().size()); assertEquals(Long.MAX_VALUE, actualOpenOrCreateResult.getMaxPageSize()); - assertEquals(1, actualOpenOrCreateResult.getMapNames().size()); + assertEquals(0, actualOpenOrCreateResult.getMapNames().size()); assertEquals(48, actualOpenOrCreateResult.getKeysPerPage()); assertEquals(0, actualOpenOrCreateResult.getAutoCommitMemory()); } diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/NitriteMVStoreTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/NitriteMVStoreTest.java index 99968fe49..955748e22 100644 --- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/NitriteMVStoreTest.java +++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/mvstore/NitriteMVStoreTest.java @@ -38,7 +38,7 @@ public void testOpenOrCreate() { nitriteMVStore.openOrCreate(); assertFalse(nitriteMVStore.isReadOnly()); assertFalse(nitriteMVStore.isClosed()); - assertTrue(nitriteMVStore.hasUnsavedChanges()); + assertFalse(nitriteMVStore.hasUnsavedChanges()); } @Test diff --git a/nitrite-mvstore-adapter/src/test/resources/no2-v3.db b/nitrite-mvstore-adapter/src/test/resources/no2-v3.db new file mode 100644 index 000000000..c9ace3b5d Binary files /dev/null and b/nitrite-mvstore-adapter/src/test/resources/no2-v3.db differ diff --git a/nitrite-rocksdb-adapter/pom.xml b/nitrite-rocksdb-adapter/pom.xml index 24f1baae3..b7acfa613 100644 --- a/nitrite-rocksdb-adapter/pom.xml +++ b/nitrite-rocksdb-adapter/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-rocksdb-adapter @@ -180,6 +180,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2.rocksdb + + + + diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/NitriteTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/NitriteTest.java index c2be82757..54754934a 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/NitriteTest.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/NitriteTest.java @@ -28,8 +28,8 @@ import org.dizitart.no2.common.SortOrder; import org.dizitart.no2.common.concurrent.ThreadPoolManager; import org.dizitart.no2.common.mapper.EntityConverter; -import org.dizitart.no2.common.mapper.SimpleNitriteMapper; import org.dizitart.no2.common.mapper.NitriteMapper; +import org.dizitart.no2.common.mapper.SimpleNitriteMapper; import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.exceptions.ValidationException; import org.dizitart.no2.index.IndexOptions; @@ -40,7 +40,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -477,9 +476,7 @@ public CompatChild fromDocument(Document document, NitriteMapper nitriteMapper) @Data @NoArgsConstructor @AllArgsConstructor - @Indices({ - @Index(fields = "synced", type = IndexType.NON_UNIQUE) - }) + @Index(fields = "synced", type = IndexType.NON_UNIQUE) public static class Receipt { @Id private String clientRef; diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java index 7d85df533..3bae9034a 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/NitriteStressTest.java @@ -35,7 +35,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.*; import uk.co.jemos.podam.api.PodamFactory; import uk.co.jemos.podam.api.PodamFactoryImpl; @@ -368,11 +367,9 @@ public PerfTest fromDocument(Document document, NitriteMapper nitriteMapper) { } } - @Indices({ - @Index(fields = "firstName", type = IndexType.NON_UNIQUE), - @Index(fields = "age", type = IndexType.NON_UNIQUE), - @Index(fields = "text", type = IndexType.FULL_TEXT), - }) + @Index(fields = "firstName", type = IndexType.NON_UNIQUE) + @Index(fields = "age", type = IndexType.NON_UNIQUE) + @Index(fields = "text", type = IndexType.FULL_TEXT) private static class PerfTestIndexed extends PerfTest { public static class Converter implements EntityConverter { diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java index 7dedc072f..4d7814e5b 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java @@ -822,4 +822,32 @@ public void testByIdFilter() { result = collection.find(or(byId(nitriteId), where("tag").eq(document.get("tag")))).firstOrNull(); assertEquals(document, result); } + + @Test + public void testByNonExistingId() { + Document doc1 = createDocument("age", 31).put("tag", "one"); + Document doc2 = createDocument("age", 32).put("tag", "two"); + Document doc3 = createDocument("age", 33).put("tag", "three"); + Document doc4 = createDocument("age", 34).put("tag", "four"); + Document doc5 = createDocument("age", 35).put("tag", "five"); + + NitriteCollection collection = db.getCollection("tag"); + collection.insert(doc1, doc2, doc3, doc4, doc5); + + NitriteId nitriteId = NitriteId.newId(); + Document result = collection.find(byId(nitriteId)).firstOrNull(); + assertNull(result); + + result = collection.find(and(byId(nitriteId), where("age").notEq(null))).firstOrNull(); + assertNull(result); + + result = collection.find(or(byId(nitriteId), where("tag").eq("one"))).firstOrNull(); + assertNotNull(result); + assertEquals(result.get("tag"), "one"); + + DocumentCursor cursor = collection.find(where("_id").eq(nitriteId.getIdValue())); + Iterator idIter = cursor.iterator(); + assertFalse(idIter.hasNext()); + assertEquals(cursor.size(), 0); + } } diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java index 80c1dd974..fa3f0da8a 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java @@ -34,7 +34,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.dizitart.no2.rocksdb.RocksDBModule; import org.junit.After; import org.junit.Before; @@ -122,11 +121,9 @@ public void testFindByEmbeddedField() { @ToString @EqualsAndHashCode - @Indices({ - @Index(fields = "joinDate", type = IndexType.NON_UNIQUE), - @Index(fields = "address", type = IndexType.FULL_TEXT), - @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) - }) + @Index(fields = "joinDate", type = IndexType.NON_UNIQUE) + @Index(fields = "address", type = IndexType.FULL_TEXT) + @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) public static class EmployeeForCustomSeparator implements Serializable { @Id @Getter diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java index c44e6ce63..1818909f2 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java @@ -30,7 +30,6 @@ import org.dizitart.no2.repository.Cursor; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.dizitart.no2.rocksdb.RocksDBModule; import org.junit.After; import org.junit.Before; @@ -165,9 +164,7 @@ public void testUniversalFullTextIndexing() { } } - @Indices( - @Index(fields = "text", type = IndexType.FULL_TEXT) - ) + @Index(fields = "text", type = IndexType.FULL_TEXT) public static class TextData { public Integer id; public String text; diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java index d720ceee4..86b927638 100644 --- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java +++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/integration/repository/data/Company.java @@ -25,7 +25,6 @@ import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import java.io.Serializable; import java.util.Date; @@ -37,9 +36,7 @@ */ @Getter @EqualsAndHashCode -@Indices({ - @Index(fields = "companyName") -}) +@Index(fields = "companyName") public class Company implements Serializable { @Id(fieldName = "company_id") @Setter diff --git a/nitrite-spatial/pom.xml b/nitrite-spatial/pom.xml index 7eec775d9..53bb5b241 100644 --- a/nitrite-spatial/pom.xml +++ b/nitrite-spatial/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-spatial @@ -125,6 +125,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2.spatial + + + + diff --git a/nitrite-support/pom.xml b/nitrite-support/pom.xml index 82aba0c97..a4769f78f 100644 --- a/nitrite-support/pom.xml +++ b/nitrite-support/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite-support @@ -133,6 +133,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2.support + + + + diff --git a/nitrite-support/src/test/java/org/dizitart/no2/support/data/Company.java b/nitrite-support/src/test/java/org/dizitart/no2/support/data/Company.java index f49d93e55..9bc6da107 100644 --- a/nitrite-support/src/test/java/org/dizitart/no2/support/data/Company.java +++ b/nitrite-support/src/test/java/org/dizitart/no2/support/data/Company.java @@ -22,7 +22,6 @@ import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import java.io.Serializable; import java.util.Date; @@ -33,9 +32,7 @@ * @author Anindya Chatterjee. */ @Data -@Indices({ - @Index(fields = "companyName") -}) +@Index(fields = "companyName") public class Company implements Serializable { @Id(fieldName = "company_id") private Long companyId; diff --git a/nitrite-support/src/test/java/org/dizitart/no2/support/data/Employee.java b/nitrite-support/src/test/java/org/dizitart/no2/support/data/Employee.java index 5c7ed6d4d..0949904c5 100644 --- a/nitrite-support/src/test/java/org/dizitart/no2/support/data/Employee.java +++ b/nitrite-support/src/test/java/org/dizitart/no2/support/data/Employee.java @@ -22,11 +22,10 @@ import lombok.ToString; import org.dizitart.no2.collection.Document; import org.dizitart.no2.common.mapper.EntityConverter; +import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.index.IndexType; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; -import org.dizitart.no2.common.mapper.NitriteMapper; import java.io.Serializable; import java.util.Date; @@ -36,11 +35,9 @@ */ @ToString @EqualsAndHashCode -@Indices({ - @Index(fields = "joinDate", type = IndexType.NON_UNIQUE), - @Index(fields = "address", type = IndexType.FULL_TEXT), - @Index(fields = "employeeNote.text", type = IndexType.FULL_TEXT) -}) +@Index(fields = "joinDate", type = IndexType.NON_UNIQUE) +@Index(fields = "address", type = IndexType.FULL_TEXT) +@Index(fields = "employeeNote.text", type = IndexType.FULL_TEXT) public class Employee implements Serializable { @Id @Getter diff --git a/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/BaseExternalTest.java b/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/BaseExternalTest.java index e130914c6..6e53f5ef1 100644 --- a/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/BaseExternalTest.java +++ b/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/BaseExternalTest.java @@ -31,7 +31,6 @@ import org.junit.Rule; import java.io.File; -import java.io.IOException; import java.util.List; import java.util.UUID; @@ -64,7 +63,7 @@ public void setUp() { } @After - public void cleanUp() throws IOException { + public void cleanUp() { closeDb(); TestUtil.deleteDb(sourceDbFile); TestUtil.deleteDb(destDbFile); diff --git a/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/ExporterTest.java b/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/ExporterTest.java index e8a7b8e60..1d1dee735 100644 --- a/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/ExporterTest.java +++ b/nitrite-support/src/test/java/org/dizitart/no2/support/exchange/ExporterTest.java @@ -1,62 +1,15 @@ package org.dizitart.no2.support.exchange; -import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.cfg.ContextAttributes; -import com.fasterxml.jackson.databind.introspect.VisibilityChecker; -import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; -import com.fasterxml.jackson.databind.jsontype.SubtypeResolver; -import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; -import com.fasterxml.jackson.databind.jsontype.impl.StdSubtypeResolver; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.type.TypeFactory; -import org.dizitart.no2.support.exchange.Exporter; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; public class ExporterTest { @Test public void testCreateObjectMapper() { ObjectMapper actualCreateObjectMapperResult = Exporter.createObjectMapper(); - DeserializationConfig deserializationConfig = actualCreateObjectMapperResult.getDeserializationConfig(); - assertTrue(actualCreateObjectMapperResult - .getSerializerFactory() instanceof com.fasterxml.jackson.databind.ser.BeanSerializerFactory); - PolymorphicTypeValidator polymorphicTypeValidator = actualCreateObjectMapperResult.getPolymorphicTypeValidator(); - assertTrue(polymorphicTypeValidator instanceof LaissezFaireSubTypeValidator); - assertTrue(actualCreateObjectMapperResult - .getDeserializationContext() instanceof com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.Impl); - assertSame(actualCreateObjectMapperResult.getFactory(), actualCreateObjectMapperResult.getJsonFactory()); - assertTrue(actualCreateObjectMapperResult - .getSerializerProviderInstance() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - VisibilityChecker visibilityChecker = actualCreateObjectMapperResult.getVisibilityChecker(); - assertTrue(visibilityChecker instanceof VisibilityChecker.Std); - assertNull(actualCreateObjectMapperResult.getPropertyNamingStrategy()); - assertTrue(actualCreateObjectMapperResult - .getSerializerProvider() instanceof com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.Impl); - SubtypeResolver subtypeResolver = actualCreateObjectMapperResult.getSubtypeResolver(); - assertTrue(subtypeResolver instanceof StdSubtypeResolver); - assertNull(deserializationConfig.getProblemHandlers()); - assertSame(visibilityChecker, deserializationConfig.getDefaultVisibilityChecker()); - assertTrue(deserializationConfig - .getClassIntrospector() instanceof com.fasterxml.jackson.databind.introspect.BasicClassIntrospector); - assertTrue(deserializationConfig.isAnnotationProcessingEnabled()); - assertNull(deserializationConfig.getPropertyNamingStrategy()); - TypeFactory expectedTypeFactory = actualCreateObjectMapperResult.getTypeFactory(); - assertSame(expectedTypeFactory, deserializationConfig.getTypeFactory()); - assertTrue(deserializationConfig.getAttributes() instanceof ContextAttributes.Impl); - JsonNodeFactory expectedNodeFactory = actualCreateObjectMapperResult.getNodeFactory(); - assertSame(expectedNodeFactory, deserializationConfig.getNodeFactory()); - assertNull(deserializationConfig.getDefaultMergeable()); - assertNull(deserializationConfig.getHandlerInstantiator()); - assertSame(actualCreateObjectMapperResult.getDateFormat(), deserializationConfig.getDateFormat()); - assertNull(deserializationConfig.getFullRootName()); - assertNull(deserializationConfig.getActiveView()); - assertEquals(237020288, deserializationConfig.getDeserializationFeatures()); - assertSame(subtypeResolver, deserializationConfig.getSubtypeResolver()); - assertTrue(deserializationConfig - .getAnnotationIntrospector() instanceof com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector); - assertSame(polymorphicTypeValidator, deserializationConfig.getPolymorphicTypeValidator()); + assertNotNull(actualCreateObjectMapperResult); } } diff --git a/nitrite/pom.xml b/nitrite/pom.xml index e0ee7f1ed..9025cbbcd 100644 --- a/nitrite/pom.xml +++ b/nitrite/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT nitrite @@ -218,6 +218,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.no2 + + + + diff --git a/nitrite/src/main/java/org/dizitart/no2/NitriteBuilder.java b/nitrite/src/main/java/org/dizitart/no2/NitriteBuilder.java index 84625e245..35373d9de 100644 --- a/nitrite/src/main/java/org/dizitart/no2/NitriteBuilder.java +++ b/nitrite/src/main/java/org/dizitart/no2/NitriteBuilder.java @@ -31,8 +31,8 @@ * @see Nitrite * @since 1.0 */ +@Getter public class NitriteBuilder { - @Getter /** * The Nitrite configuration object. */ @@ -61,6 +61,27 @@ public NitriteBuilder fieldSeparator(String separator) { return this; } + /** + * Disables the repository type validation for the Nitrite database. + *

+ * Repository type validation is a feature in Nitrite that ensures the type of the objects + * stored in the repository can be converted to and from {@link org.dizitart.no2.collection.Document}. + *

+ * By default, the repository type validation is enabled. If you disable it, and if you try to + * store an object that cannot be converted to a {@link org.dizitart.no2.collection.Document}, + * then Nitrite will throw an exception during the operation. + * + * @return the NitriteBuilder instance with repository type validation disabled + * @see org.dizitart.no2.collection.Document + * @see org.dizitart.no2.repository.ObjectRepository + * @see org.dizitart.no2.common.mapper.EntityConverter + * @since 4.3.0 + */ + public NitriteBuilder disableRepositoryTypeValidation() { + this.nitriteConfig.disableRepositoryTypeValidation(); + return this; + } + /** * Registers an {@link EntityConverter} with the Nitrite database. * An {@link EntityConverter} is used to convert between an entity and a diff --git a/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java b/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java index ae8f3ac40..0c2d043b9 100644 --- a/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java +++ b/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java @@ -79,6 +79,12 @@ public class NitriteConfig implements AutoCloseable { */ private Integer schemaVersion = Constants.INITIAL_SCHEMA_VERSION; + @Getter + /** + * Indicates if repository type validation is disabled. + */ + private boolean repositoryTypeValidationDisabled = false; + /** * Instantiates a new {@link NitriteConfig}. */ @@ -103,6 +109,20 @@ public void fieldSeparator(String separator) { NitriteConfig.fieldSeparator = separator; } + /** + * Disables repository type validation. + * + * @throws InvalidOperationException if the repository type validation is attempted to be + * changed after database initialization. + */ + public void disableRepositoryTypeValidation() { + if (configured) { + throw new InvalidOperationException("Cannot change repository type validation after database" + + " initialization"); + } + this.repositoryTypeValidationDisabled = true; + } + /** * Registers an {@link EntityConverter} with the Nitrite database. * @@ -157,7 +177,7 @@ public NitriteConfig addMigration(Migration migration) { TreeMap targetMap = migrations.computeIfAbsent(start, k -> new TreeMap<>()); Migration existing = targetMap.get(end); if (existing != null) { - log.warn("Overriding migration " + existing + " with " + migration); + log.warn("Overriding migration {} with {}", existing, migration); } targetMap.put(end, migration); } diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java b/nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java index 314d08619..513b732f0 100644 --- a/nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java +++ b/nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java @@ -176,8 +176,14 @@ public Document merge(Document document) { // if the value is a document, merge it recursively if (containsKey(key)) { // if the current document already contains the key, - // then merge the embedded document - get(key, Document.class).merge((Document) value); + // and the value is not null, merge it + Document pairs = get(key, Document.class); + if (pairs != null) { + pairs.merge((Document) value); + } else { + //otherwise, just set the value to whatever was provided + put(key, value); + } } else { // if the current document does not contain the key, // then put the embedded document as it is diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/ReadOperations.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/ReadOperations.java index 807b47d98..3cf02c575 100644 --- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/ReadOperations.java +++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/ReadOperations.java @@ -136,8 +136,12 @@ private RecordStream> findSuitableStream(FindPlan find if (findPlan.getByIdFilter() != null) { FieldBasedFilter byIdFilter = findPlan.getByIdFilter(); NitriteId nitriteId = NitriteId.createId((String) byIdFilter.getValue()); - Document document = nitriteMap.get(nitriteId); - rawStream = RecordStream.single(pair(nitriteId, document)); + if (nitriteMap.containsKey(nitriteId)) { + Document document = nitriteMap.get(nitriteId); + rawStream = RecordStream.single(pair(nitriteId, document)); + } else { + rawStream = RecordStream.empty(); + } } else { IndexDescriptor indexDescriptor = findPlan.getIndexDescriptor(); if (indexDescriptor != null) { diff --git a/nitrite/src/main/java/org/dizitart/no2/common/util/ValidationUtils.java b/nitrite/src/main/java/org/dizitart/no2/common/util/ValidationUtils.java index 6adfcb860..2c664eb53 100644 --- a/nitrite/src/main/java/org/dizitart/no2/common/util/ValidationUtils.java +++ b/nitrite/src/main/java/org/dizitart/no2/common/util/ValidationUtils.java @@ -16,6 +16,7 @@ package org.dizitart.no2.common.util; +import org.dizitart.no2.NitriteConfig; import org.dizitart.no2.collection.Document; import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.exceptions.IndexingException; @@ -149,7 +150,7 @@ public static void validateProjectionType(Class type, NitriteMapper nitriteMa } } - public static void validateRepositoryType(Class type, NitriteMapper nitriteMapper) { + public static void validateRepositoryType(Class type, NitriteConfig nitriteConfig) { Object value; try { if (type.isInterface() || (Modifier.isAbstract(type.getModifiers()) && !isBuiltInValueType(type))) { @@ -157,14 +158,17 @@ public static void validateRepositoryType(Class type, NitriteMapper nitriteMa return; } - value = newInstance(type, false, nitriteMapper); - if (value == null) { - throw new ValidationException("Cannot create new instance of type " + type); - } - - Document document = (Document) nitriteMapper.tryConvert(value, Document.class); - if (document == null || document.size() == 0) { - throw new ValidationException("Cannot convert to document from type " + type); + if (!nitriteConfig.isRepositoryTypeValidationDisabled()) { + NitriteMapper nitriteMapper = nitriteConfig.nitriteMapper(); + value = newInstance(type, false, nitriteMapper); + if (value == null) { + throw new ValidationException("Cannot create new instance of type " + type); + } + + Document document = (Document) nitriteMapper.tryConvert(value, Document.class); + if (document == null || document.size() == 0) { + throw new ValidationException("Cannot convert to document from type " + type); + } } } catch (Exception e) { throw new ValidationException("Invalid repository type", e); diff --git a/nitrite/src/main/java/org/dizitart/no2/repository/AnnotationScanner.java b/nitrite/src/main/java/org/dizitart/no2/repository/AnnotationScanner.java index ca2d78c6d..ec44bad6d 100644 --- a/nitrite/src/main/java/org/dizitart/no2/repository/AnnotationScanner.java +++ b/nitrite/src/main/java/org/dizitart/no2/repository/AnnotationScanner.java @@ -101,9 +101,8 @@ private void scanIndexAnnotation() { if (type.isAnnotationPresent(InheritIndices.class)) { indexList = reflector.findInheritedAnnotations(Index.class, type); } else { - indexList = new ArrayList<>(); - Index index = type.getAnnotation(Index.class); - if (index != null) indexList.add(index); + Index[] indexes = type.getAnnotationsByType(Index.class); + indexList = new ArrayList<>(Arrays.asList(indexes)); } populateIndex(indexList); } diff --git a/nitrite/src/main/java/org/dizitart/no2/repository/RepositoryFactory.java b/nitrite/src/main/java/org/dizitart/no2/repository/RepositoryFactory.java index 06a7c302f..2d2cf72f5 100644 --- a/nitrite/src/main/java/org/dizitart/no2/repository/RepositoryFactory.java +++ b/nitrite/src/main/java/org/dizitart/no2/repository/RepositoryFactory.java @@ -19,7 +19,6 @@ import org.dizitart.no2.NitriteConfig; import org.dizitart.no2.collection.CollectionFactory; import org.dizitart.no2.collection.NitriteCollection; -import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.common.util.StringUtils; import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.exceptions.ValidationException; @@ -133,10 +132,9 @@ public void clear() { private ObjectRepository createRepository(NitriteConfig nitriteConfig, Class type, String collectionName, String key) { - NitriteMapper nitriteMapper = nitriteConfig.nitriteMapper(); NitriteStore store = nitriteConfig.getNitriteStore(); - validateRepositoryType(type, nitriteMapper); + validateRepositoryType(type, nitriteConfig); if (store.getCollectionNames().contains(collectionName)) { throw new ValidationException("A collection with same entity name already exists"); @@ -154,14 +152,13 @@ private ObjectRepository createRepository(NitriteConfig nitriteConfig, Cl private ObjectRepository createRepositoryByDecorator(NitriteConfig nitriteConfig, EntityDecorator entityDecorator, String collectionName, String key) { - NitriteMapper nitriteMapper = nitriteConfig.nitriteMapper(); NitriteStore store = nitriteConfig.getNitriteStore(); if (store.getCollectionNames().contains(collectionName)) { throw new ValidationException("A collection with same entity name already exists"); } - validateRepositoryType(entityDecorator.getEntityType(), nitriteMapper); + validateRepositoryType(entityDecorator.getEntityType(), nitriteConfig); NitriteCollection nitriteCollection = collectionFactory.getCollection(collectionName, nitriteConfig, false); diff --git a/nitrite/src/test/java/org/dizitart/no2/common/util/ValidationUtilsTest.java b/nitrite/src/test/java/org/dizitart/no2/common/util/ValidationUtilsTest.java index 5a8e0b17d..5cc36012e 100644 --- a/nitrite/src/test/java/org/dizitart/no2/common/util/ValidationUtilsTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/common/util/ValidationUtilsTest.java @@ -16,6 +16,7 @@ package org.dizitart.no2.common.util; +import org.dizitart.no2.NitriteConfig; import org.dizitart.no2.common.mapper.SimpleNitriteMapper; import org.dizitart.no2.exceptions.ValidationException; import org.dizitart.no2.integration.Retry; @@ -96,18 +97,19 @@ public void testValidateProjectionType() { @Test public void testValidateRepositoryType() { - SimpleNitriteMapper documentMapper = new SimpleNitriteMapper(); - documentMapper.registerEntityConverter(new ClassA.ClassAConverter()); - documentMapper.registerEntityConverter(new ClassBConverter()); - documentMapper.registerEntityConverter(new EmptyClass.Converter()); + NitriteConfig nitriteConfig = new NitriteConfig(); + nitriteConfig.registerEntityConverter(new ClassA.ClassAConverter()); + nitriteConfig.registerEntityConverter(new ClassBConverter()); + nitriteConfig.registerEntityConverter(new EmptyClass.Converter()); + nitriteConfig.autoConfigure(); - validateRepositoryType(ClassA.class, documentMapper); + validateRepositoryType(ClassA.class, nitriteConfig); - assertThrows(ValidationException.class, () -> validateRepositoryType(EmptyClass.class, documentMapper)); - assertThrows(ValidationException.class, () -> validateRepositoryType(ClassC.class, documentMapper)); - assertThrows(ValidationException.class, () -> validateRepositoryType(String.class, documentMapper)); - assertThrows(ValidationException.class, () -> validateRepositoryType(Number.class, documentMapper)); - assertThrows(ValidationException.class, () -> validateRepositoryType(Integer.class, documentMapper)); - assertThrows(ValidationException.class, () -> validateRepositoryType(Object.class, documentMapper)); + assertThrows(ValidationException.class, () -> validateRepositoryType(EmptyClass.class, nitriteConfig)); + assertThrows(ValidationException.class, () -> validateRepositoryType(ClassC.class, nitriteConfig)); + assertThrows(ValidationException.class, () -> validateRepositoryType(String.class, nitriteConfig)); + assertThrows(ValidationException.class, () -> validateRepositoryType(Number.class, nitriteConfig)); + assertThrows(ValidationException.class, () -> validateRepositoryType(Integer.class, nitriteConfig)); + assertThrows(ValidationException.class, () -> validateRepositoryType(Object.class, nitriteConfig)); } } diff --git a/nitrite/src/test/java/org/dizitart/no2/filters/TextFilterTest.java b/nitrite/src/test/java/org/dizitart/no2/filters/TextFilterTest.java index a9066378f..91323357f 100644 --- a/nitrite/src/test/java/org/dizitart/no2/filters/TextFilterTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/filters/TextFilterTest.java @@ -17,12 +17,18 @@ package org.dizitart.no2.filters; +import org.dizitart.no2.collection.Document; +import org.dizitart.no2.collection.NitriteId; +import org.dizitart.no2.common.tuples.Pair; import org.dizitart.no2.exceptions.FilterException; import org.dizitart.no2.index.fulltext.EnglishTextTokenizer; import org.dizitart.no2.store.memory.InMemoryMap; import org.junit.Test; +import org.mockito.Mockito; import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class TextFilterTest { @Test @@ -61,7 +67,23 @@ public void testApplyOnIndex3() { TextFilter textFilter = new TextFilter("Field", "*"); textFilter.setTextTokenizer(new EnglishTextTokenizer()); assertThrows(FilterException.class, - () -> textFilter.applyOnTextIndex(new InMemoryMap<>("Map Name", null))); + () -> textFilter.applyOnTextIndex(new InMemoryMap<>("Map Name", null))); + } + + @Test + public void applyTestWhenDocStringContainsSearchString() { + //Arrange + TextFilter textFilter = new TextFilter("fieldString", "string"); + Document docMock = mock(Document.class); + Pair pairElementMock = mock(Pair.class); + when(pairElementMock.getSecond()).thenReturn(docMock); + when(docMock.get(Mockito.anyString())).thenReturn("parent doc string"); + + //Action + var result = textFilter.apply(pairElementMock); + //Assert + assertTrue(result); + } } diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/NitriteTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/NitriteTest.java index 143bc56bb..5c59a67d0 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/NitriteTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/NitriteTest.java @@ -38,7 +38,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -428,9 +427,7 @@ public CompatChild fromDocument(Document document, NitriteMapper nitriteMapper) @Data @NoArgsConstructor @AllArgsConstructor - @Indices({ - @Index(fields = "synced", type = IndexType.NON_UNIQUE) - }) + @Index(fields = "synced", type = IndexType.NON_UNIQUE) public static class Receipt { @Id private String clientRef; diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/StressTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/StressTest.java index f7817a1cb..89542a967 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/StressTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/StressTest.java @@ -30,7 +30,6 @@ import org.dizitart.no2.index.IndexType; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -193,11 +192,9 @@ public PerfTest fromDocument(Document document, NitriteMapper nitriteMapper) { } } - @Indices({ - @Index(fields = "firstName", type = IndexType.NON_UNIQUE), - @Index(fields = "age", type = IndexType.NON_UNIQUE), - @Index(fields = "text", type = IndexType.FULL_TEXT), - }) + @Index(fields = "firstName", type = IndexType.NON_UNIQUE) + @Index(fields = "age", type = IndexType.NON_UNIQUE) + @Index(fields = "text", type = IndexType.FULL_TEXT) private static class PerfTestIndexed extends PerfTest { public static class PerfTestIndexedConverter implements EntityConverter { diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java index 5fd707307..49c501185 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionFindTest.java @@ -852,4 +852,32 @@ public void testByIdFilter() { result = collection.find(or(byId(nitriteId), where("tag").eq(document.get("tag")))).firstOrNull(); assertEquals(document, result); } + + @Test + public void testByNonExistingId() { + Document doc1 = createDocument("age", 31).put("tag", "one"); + Document doc2 = createDocument("age", 32).put("tag", "two"); + Document doc3 = createDocument("age", 33).put("tag", "three"); + Document doc4 = createDocument("age", 34).put("tag", "four"); + Document doc5 = createDocument("age", 35).put("tag", "five"); + + NitriteCollection collection = db.getCollection("tag"); + collection.insert(doc1, doc2, doc3, doc4, doc5); + + NitriteId nitriteId = NitriteId.newId(); + Document result = collection.find(byId(nitriteId)).firstOrNull(); + assertNull(result); + + result = collection.find(and(byId(nitriteId), where("age").notEq(null))).firstOrNull(); + assertNull(result); + + result = collection.find(or(byId(nitriteId), where("tag").eq("one"))).firstOrNull(); + assertNotNull(result); + assertEquals(result.get("tag"), "one"); + + DocumentCursor cursor = collection.find(where("_id").eq(nitriteId.getIdValue())); + Iterator idIter = cursor.iterator(); + assertFalse(idIter.hasNext()); + assertEquals(cursor.size(), 0); + } } diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionUpdateTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionUpdateTest.java index 4dad51555..959a2b3c0 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionUpdateTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/collection/CollectionUpdateTest.java @@ -17,10 +17,7 @@ package org.dizitart.no2.integration.collection; -import org.dizitart.no2.collection.Document; -import org.dizitart.no2.collection.DocumentCursor; -import org.dizitart.no2.collection.NitriteCollection; -import org.dizitart.no2.collection.UpdateOptions; +import org.dizitart.no2.collection.*; import org.dizitart.no2.common.WriteResult; import org.dizitart.no2.exceptions.NitriteIOException; import org.dizitart.no2.exceptions.NotIdentifiableException; @@ -299,4 +296,18 @@ public void testIssue151() { assertEquals(coll.find(where("fruit").eq("Apple")).size(), 1); } + + @Test + public void testUpdatePreviouslyNullObject() { + Document doc1 = createDocument().put("fruitType", null); + NitriteCollection coll = db.getCollection("test"); + + WriteResult insert = coll.insert(doc1); + NitriteId next = insert.iterator().next(); + Document doc2 = createDocument().put("_id", next.getIdValue()).put("fruitType", createDocument().put("family", "citric")); + coll.update(doc2); + + assertEquals(coll.find(where("_id").eq(next.getIdValue())).size(), 1); + assertNotNull(coll.find(where("_id").eq(next.getIdValue())).firstOrNull().get("fruitType")); + } } diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java index a562a1506..c354e885e 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/repository/CustomFieldSeparatorTest.java @@ -34,7 +34,6 @@ import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -110,37 +109,25 @@ public void testFindByEmbeddedField() { assertEquals(repository.find(where("company:companyName").eq("Dummy Company")).size(), 1); } + @Setter + @Getter @ToString @EqualsAndHashCode - @Indices({ - @Index(fields = "joinDate", type = IndexType.NON_UNIQUE), - @Index(fields = "address", type = IndexType.FULL_TEXT), - @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) - }) + @Index(fields = "joinDate", type = IndexType.NON_UNIQUE) + @Index(fields = "address", type = IndexType.FULL_TEXT) + @Index(fields = "employeeNote:text", type = IndexType.FULL_TEXT) public static class EmployeeForCustomSeparator implements Serializable { @Id - @Getter - @Setter private Long empId; - @Getter - @Setter private Date joinDate; - @Getter - @Setter private String address; - @Getter - @Setter private Company company; - @Getter - @Setter private byte[] blob; - @Getter - @Setter private Note employeeNote; EmployeeForCustomSeparator() { diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java b/nitrite/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java index b05a998ea..c0c8826ca 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/repository/UniversalTextTokenizerTest.java @@ -30,7 +30,6 @@ import org.dizitart.no2.repository.Cursor; import org.dizitart.no2.repository.ObjectRepository; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -153,9 +152,7 @@ public void testUniversalFullTextIndexing() { } } - @Indices( - @Index(fields = "text", type = IndexType.FULL_TEXT) - ) + @Index(fields = "text", type = IndexType.FULL_TEXT) public static class TextData { public Integer id; public String text; diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Company.java b/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Company.java index d720ceee4..86b927638 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Company.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Company.java @@ -25,7 +25,6 @@ import org.dizitart.no2.common.mapper.NitriteMapper; import org.dizitart.no2.repository.annotations.Id; import org.dizitart.no2.repository.annotations.Index; -import org.dizitart.no2.repository.annotations.Indices; import java.io.Serializable; import java.util.Date; @@ -37,9 +36,7 @@ */ @Getter @EqualsAndHashCode -@Indices({ - @Index(fields = "companyName") -}) +@Index(fields = "companyName") public class Company implements Serializable { @Id(fieldName = "company_id") @Setter diff --git a/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Employee.java b/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Employee.java index 2fa4f5aef..c95dc77e4 100644 --- a/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Employee.java +++ b/nitrite/src/test/java/org/dizitart/no2/integration/repository/data/Employee.java @@ -34,6 +34,8 @@ /** * @author Anindya Chatterjee. */ +@Setter +@Getter @ToString @EqualsAndHashCode @Index(fields = "joinDate", type = IndexType.NON_UNIQUE) @@ -41,32 +43,18 @@ @Index(fields = "employeeNote.text", type = IndexType.FULL_TEXT) public class Employee implements Serializable { @Id - @Getter - @Setter private Long empId; - @Getter - @Setter private Date joinDate; - @Getter - @Setter private String address; - @Getter - @Setter private String emailAddress; - @Getter - @Setter private transient Company company; - @Getter - @Setter private byte[] blob; - @Getter - @Setter private Note employeeNote; public Employee() { diff --git a/nitrite/src/test/java/org/dizitart/no2/migration/MigrationManagerTest.java b/nitrite/src/test/java/org/dizitart/no2/migration/MigrationManagerTest.java new file mode 100644 index 000000000..e79c55e3d --- /dev/null +++ b/nitrite/src/test/java/org/dizitart/no2/migration/MigrationManagerTest.java @@ -0,0 +1,36 @@ +package org.dizitart.no2.migration; + +import org.dizitart.no2.Nitrite; +import org.dizitart.no2.NitriteConfig; +import org.dizitart.no2.store.StoreMetaData; +import org.junit.Test; +import org.mockito.Mockito; + +import java.lang.reflect.Method; +import java.util.Queue; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.when; + +public class MigrationManagerTest { + + @Test + @SuppressWarnings("unchecked") + public void findMigrationPathTestWhenStartAndEndAreSame() throws Exception { + NitriteConfig nitriteConfigMock = Mockito.mock(NitriteConfig.class); + StoreMetaData storeMetaDataMock = Mockito.mock(StoreMetaData.class); + + Nitrite nitriteMock = Mockito.mock(Nitrite.class); + when(nitriteMock.getConfig()).thenReturn(nitriteConfigMock); + + MigrationManager migrationManager = new MigrationManager(nitriteMock); + + when(nitriteMock.getDatabaseMetaData()).thenReturn(storeMetaDataMock); + + Method method = MigrationManager.class.getDeclaredMethod("findMigrationPath", int.class, int.class); + method.setAccessible(true); + var result = (Queue) method.invoke(migrationManager, 1, 1); + + assertNotNull(result); + } +} diff --git a/nitrite/src/test/java/org/dizitart/no2/store/UserAuthenticationServiceTest.java b/nitrite/src/test/java/org/dizitart/no2/store/UserAuthenticationServiceTest.java index e746d73ca..c0b19c9ae 100644 --- a/nitrite/src/test/java/org/dizitart/no2/store/UserAuthenticationServiceTest.java +++ b/nitrite/src/test/java/org/dizitart/no2/store/UserAuthenticationServiceTest.java @@ -17,8 +17,13 @@ package org.dizitart.no2.store; +import org.dizitart.no2.exceptions.NitriteSecurityException; import org.dizitart.no2.store.memory.InMemoryStore; import org.junit.Test; +import org.mockito.Mockito; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class UserAuthenticationServiceTest { @Test @@ -45,5 +50,38 @@ public void testAuthenticate4() { public void testAuthenticate5() { (new UserAuthenticationService(new InMemoryStore())).authenticate("", "iloveyou"); } + + @Test(expected = NitriteSecurityException.class) + public void testAuthenticateIfUsernamePasswordAreNull() { + //region ARRANGE + NitriteStore storeMock = mock(NitriteStore.class); + when(storeMock.hasMap(Mockito.anyString())).thenReturn(true); + + UserAuthenticationService userAuthenticationService = new UserAuthenticationService(storeMock); + //endregion + + //region ACTION + userAuthenticationService.authenticate(null, null); + //endregion + } + + @Test(expected = NitriteSecurityException.class) + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testAuthenticateIfHasMapIsTrueAndUserCredentialIsNull() { + //region ARRANGE + NitriteMap nitriteMapMock = mock(NitriteMap.class); + when(nitriteMapMock.get(Mockito.anyString())).thenReturn(null); + + NitriteStore storeMock = mock(NitriteStore.class); + when(storeMock.hasMap(Mockito.anyString())).thenReturn(true); + when(storeMock.openMap(Mockito.anyString(), Mockito.any(), Mockito.any())).thenReturn(nitriteMapMock); + + UserAuthenticationService userAuthenticationService = new UserAuthenticationService(storeMock); + //endregion + + //region ACTION + userAuthenticationService.authenticate("usernameString", "passwordString"); + //endregion + } } diff --git a/pom.xml b/pom.xml index 08f61159c..6cc83295d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT pom Nitrite Database @@ -51,44 +51,45 @@ 11 11 UTF-8 - 2.16.1 - 2.0.12 + 2.17.1 + 2.0.13 1.9.3 2.2.224 - 8.11.3 + 9.2.1 5.5.0 1.19.0 - 1.16.1 - 2.15.1 - 1.9.22 - 1.6.3 - 1.18.30 + 1.17.0 + 2.16.1 + 2.0.0 + 1.7.1 + 0.6.0 + 1.18.34 1.18.20.0 4.13.2 - 5.11.0 - 8.0.1.RELEASE - 2.23.0 - 4.2.0 + 5.12.0 + 8.0.2.RELEASE + 2.23.1 + 4.2.1 2.12.7 2.0.3 2.2 - 4.0.1 - 4.0.4 + 4.0.2 + 4.0.5 1.0.2 - 33.0.0-jre - 1.6.8 + 33.2.1-jre + 1.6.9 - 2.25.0 - 0.8.11 - 3.2.5 - 3.12.1 - 3.6.3 - 3.3.0 + 2.28.0 + 0.8.12 + 3.3.0 + 3.13.0 + 3.7.0 + 3.3.1 1.9.20 1.23 7.0_r2 - 1.6.13 - 3.1.0 + 1.7.0 + 3.2.4 @@ -291,6 +292,12 @@ ${kotlin.version} test + + org.jetbrains.kotlinx + kotlinx-datetime-jvm + ${kotlinx-datetime.version} + test + diff --git a/potassium-nitrite/pom.xml b/potassium-nitrite/pom.xml index ffb4a7da3..ae8835278 100644 --- a/potassium-nitrite/pom.xml +++ b/potassium-nitrite/pom.xml @@ -4,7 +4,7 @@ org.dizitart nitrite-java - 4.2.2 + 4.3.0-SNAPSHOT potassium-nitrite @@ -15,7 +15,6 @@ UTF-8 - 1.9.0 true @@ -123,6 +122,11 @@ log4j-core test + + org.jetbrains.kotlinx + kotlinx-datetime-jvm + test + @@ -166,6 +170,17 @@ org.sonatype.plugins nexus-staging-maven-plugin + + org.apache.maven.plugins + maven-jar-plugin + + + + org.dizitart.kno2 + + + + diff --git a/potassium-nitrite/src/main/kotlin/org/dizitart/kno2/Builder.kt b/potassium-nitrite/src/main/kotlin/org/dizitart/kno2/Builder.kt index eb14b6a4d..21b8cd418 100644 --- a/potassium-nitrite/src/main/kotlin/org/dizitart/kno2/Builder.kt +++ b/potassium-nitrite/src/main/kotlin/org/dizitart/kno2/Builder.kt @@ -49,6 +49,23 @@ class Builder internal constructor() { */ var fieldSeparator: String = NitriteConfig.getFieldSeparator() + /** + * Enables/disables the repository type validation for the Nitrite database. + *

+ * Repository type validation is a feature in Nitrite that ensures the type of the objects + * stored in the repository can be converted to and from [org.dizitart.no2.collection.Document]. + *

+ * By default, the repository type validation is enabled. If you disable it, and if you try to + * store an object that cannot be converted to a [org.dizitart.no2.collection.Document], + * then Nitrite will throw an exception during the operation. + * + * @see org.dizitart.no2.collection.Document + * @see org.dizitart.no2.repository.ObjectRepository + * @see org.dizitart.no2.common.mapper.EntityConverter + * @since 4.3.0 + */ + var enableRepositoryValidation = true + /** * Loads a [NitriteModule] into the Nitrite database. The module can be used to extend the * functionality of Nitrite. @@ -88,6 +105,10 @@ class Builder internal constructor() { builder.schemaVersion(schemaVersion) } + if (!enableRepositoryValidation) { + builder.disableRepositoryTypeValidation() + } + if (entityConverters.isNotEmpty()) { entityConverters.forEach { builder.registerEntityConverter(it) } } diff --git a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/KotlinXSerializationMapperTest.kt b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/KotlinXSerializationMapperTest.kt index 57c8b3678..b098fbe9d 100644 --- a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/KotlinXSerializationMapperTest.kt +++ b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/KotlinXSerializationMapperTest.kt @@ -23,6 +23,7 @@ import org.dizitart.kno2.filters.eq import org.dizitart.kno2.serialization.KotlinXSerializationMapper import org.dizitart.no2.collection.Document import org.dizitart.no2.common.module.NitriteModule.module +import org.dizitart.no2.exceptions.ValidationException import org.dizitart.no2.mvstore.MVStoreModule import org.junit.Test import org.slf4j.LoggerFactory @@ -180,4 +181,51 @@ class KotlinXSerializationMapperTest { testData.someArray.forEachIndexed { index, s -> assertEquals(decodedObject.someArray[index], s) } assertEquals(testData, decodedObject.copy(someArray = testData.someArray)) } -} \ No newline at end of file + + @Test(expected = ValidationException::class) + fun testRepositoryValidationEnabled() { + val db = nitrite { + loadModule(MVStoreModule(dbPath)) + loadModule(module(KotlinXSerializationMapper())) + } + + val repo = db.getRepository() + repo.insert(CacheEntry("sha256", kotlinx.datetime.Clock.System.now())) + repo.find(CacheEntry::sha256 eq "sha256").firstOrNull().also { + assertEquals(it?.sha256, "sha256") + } + db.close() + try { + Files.delete(Paths.get(dbPath)) + } catch (e: Exception) { + log.error("Failed to delete db file", e) + } + } + + @Test + fun testRepositoryValidationDisabled() { + val db = nitrite { + enableRepositoryValidation = false + loadModule(MVStoreModule(dbPath)) + loadModule(module(KotlinXSerializationMapper())) + } + + val repo = db.getRepository() + repo.insert(CacheEntry("sha256", kotlinx.datetime.Clock.System.now())) + repo.find(CacheEntry::sha256 eq "sha256").firstOrNull().also { + assertEquals(it?.sha256, "sha256") + } + db.close() + try { + Files.delete(Paths.get(dbPath)) + } catch (e: Exception) { + log.error("Failed to delete db file", e) + } + } +} + +@Serializable +data class CacheEntry( + val sha256: String, + val lastUpdated: kotlinx.datetime.Instant +) \ No newline at end of file diff --git a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/NitriteTest.kt b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/NitriteTest.kt index e9d9182d5..b3d9f014b 100644 --- a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/NitriteTest.kt +++ b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/NitriteTest.kt @@ -31,7 +31,6 @@ import org.dizitart.no2.repository.EntityId import org.dizitart.no2.repository.EntityIndex import org.dizitart.no2.repository.annotations.Id import org.dizitart.no2.repository.annotations.Index -import org.dizitart.no2.repository.annotations.Indices import org.dizitart.no2.repository.annotations.InheritIndices import org.junit.Assert.* import org.junit.Before @@ -222,7 +221,7 @@ interface MyInterface { val id: UUID } -@Indices(value = [(Index(fields = ["name"], type = IndexType.NON_UNIQUE))]) +@Index(fields = ["name"], type = IndexType.NON_UNIQUE) abstract class SomeAbsClass( @Id override val id: UUID = UUID.randomUUID(), open val name: String = "abcd" @@ -249,7 +248,7 @@ data class CaObject( val name: String = "" ) -@Indices(value = [(Index(fields = ["time"], type = IndexType.UNIQUE))]) +@Index(fields = ["time"], type = IndexType.UNIQUE) data class ClassWithLocalDateTime( val name: String = "", val time: LocalDateTime = LocalDateTime.now() diff --git a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/ObjectFilterTest.kt b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/ObjectFilterTest.kt index 9657ebafd..6c3184d20 100644 --- a/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/ObjectFilterTest.kt +++ b/potassium-nitrite/src/test/kotlin/org/dizitart/kno2/ObjectFilterTest.kt @@ -21,7 +21,6 @@ import org.dizitart.no2.index.IndexType import org.dizitart.no2.mvstore.MVStoreModule import org.dizitart.no2.repository.annotations.Id import org.dizitart.no2.repository.annotations.Index -import org.dizitart.no2.repository.annotations.Indices import org.dizitart.no2.spatial.SpatialIndexer import org.junit.Assert.assertEquals import org.junit.Before @@ -337,7 +336,7 @@ class ObjectFilterTest : BaseTest() { } } -@Indices(Index(fields = ["text"], type = IndexType.FULL_TEXT)) +@Index(fields = ["text"], type = IndexType.FULL_TEXT) data class TestData(@Id val id: Int = 0, val text: String = "", val list: List = listOf()) class ListData(val name: String = "", val score: Int = 0)