Skip to content

Commit

Permalink
Merge branch 'main' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
anidotnet committed May 16, 2024
2 parents f0c4332 + e5cfd4d commit 0d4638a
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

- 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

## Release 4.2.2 - Mar 5, 2024

Expand Down
23 changes: 22 additions & 1 deletion nitrite/src/main/java/org/dizitart/no2/NitriteBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
* @see Nitrite
* @since 1.0
*/
@Getter
public class NitriteBuilder {
@Getter
/**
* The Nitrite configuration object.
*/
Expand Down Expand Up @@ -61,6 +61,27 @@ public NitriteBuilder fieldSeparator(String separator) {
return this;
}

/**
* Disables the repository type validation for the Nitrite database.
* <p>
* 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}.
* <p>
* 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
Expand Down
22 changes: 21 additions & 1 deletion nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
*/
Expand All @@ -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.
*
Expand Down Expand Up @@ -157,7 +177,7 @@ public NitriteConfig addMigration(Migration migration) {
TreeMap<Integer, Migration> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -149,22 +150,25 @@ 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))) {
// defer validation during insertion
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -133,10 +132,9 @@ public void clear() {

private <T> ObjectRepository<T> createRepository(NitriteConfig nitriteConfig, Class<T> 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");
Expand All @@ -154,14 +152,13 @@ private <T> ObjectRepository<T> createRepository(NitriteConfig nitriteConfig, Cl
private <T> ObjectRepository<T> createRepositoryByDecorator(NitriteConfig nitriteConfig,
EntityDecorator<T> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}
11 changes: 9 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,13 @@
<jts.version>1.19.0</jts.version>
<commons-codec.version>1.17.0</commons-codec.version>
<commons-io.version>2.16.1</commons-io.version>
<kotlin.version>1.9.23</kotlin.version>
<kotlin.version>1.9.24</kotlin.version>
<kotlinx-serialization.version>1.6.3</kotlinx-serialization.version>
<kotlinx-datetime.version>0.6.0-RC.2</kotlinx-datetime.version>
<lombok.version>1.18.32</lombok.version>
<lombok-maven-plugin.version>1.18.20.0</lombok-maven-plugin.version>
<junit.version>4.13.2</junit.version>
<mockito.version>5.11.0</mockito.version>
<mockito.version>5.12.0</mockito.version>
<podam.version>8.0.1.RELEASE</podam.version>
<log4j.version>2.23.1</log4j.version>
<awaitility.version>4.2.1</awaitility.version>
Expand Down Expand Up @@ -291,6 +292,12 @@
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<version>${kotlinx-datetime.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
5 changes: 5 additions & 0 deletions potassium-nitrite/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
21 changes: 21 additions & 0 deletions potassium-nitrite/src/main/kotlin/org/dizitart/kno2/Builder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ class Builder internal constructor() {
*/
var fieldSeparator: String = NitriteConfig.getFieldSeparator()

/**
* Enables/disables the repository type validation for the Nitrite database.
* <p>
* 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].
* <p>
* 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.
Expand Down Expand Up @@ -88,6 +105,10 @@ class Builder internal constructor() {
builder.schemaVersion(schemaVersion)
}

if (!enableRepositoryValidation) {
builder.disableRepositoryTypeValidation()
}

if (entityConverters.isNotEmpty()) {
entityConverters.forEach { builder.registerEntityConverter(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -180,4 +181,51 @@ class KotlinXSerializationMapperTest {
testData.someArray.forEachIndexed { index, s -> assertEquals(decodedObject.someArray[index], s) }
assertEquals(testData, decodedObject.copy(someArray = testData.someArray))
}
}

@Test(expected = ValidationException::class)
fun testRepositoryValidationEnabled() {
val db = nitrite {
loadModule(MVStoreModule(dbPath))
loadModule(module(KotlinXSerializationMapper()))
}

val repo = db.getRepository<CacheEntry>()
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<CacheEntry>()
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
)

0 comments on commit 0d4638a

Please sign in to comment.