From cdf9351a39136b72fd76d3ad5e40821a92aab24c Mon Sep 17 00:00:00 2001
From: Anindya Chatterjee
Date: Wed, 14 Oct 2020 11:44:46 +0530
Subject: [PATCH 01/13] work in progress
---
nitrite-android-example/build.gradle | 9 +-
.../no2/test/RepositoryModificationTest.java | 8 +-
.../java/org/dizitart/no2/mapdb/MapDBMap.java | 77 +--
.../org/dizitart/no2/mapdb/MapDBStore.java | 6 +-
.../no2/mapdb/NitriteBuilderTest.java | 6 +-
.../mapdb/collection/CollectionIndexTest.java | 22 +-
.../repository/RepositoryFactoryTest.java | 4 +-
.../RepositoryModificationTest.java | 8 +-
.../dizitart/no2/mvstore/NitriteMVMap.java | 5 +
.../dizitart/no2/mvstore/ReverseIterator.java | 42 ++
.../no2/mvstore/compat/v3/MigrationUtil.java | 10 +-
.../org/dizitart/no2/NitriteBuilderTest.java | 6 +-
.../no2/collection/CollectionIndexTest.java | 22 +-
.../no2/repository/RepositoryFactoryTest.java | 4 +-
.../RepositoryModificationTest.java | 8 +-
.../no2/sync/ReplicationTemplate.java | 4 +-
.../org/dizitart/no2/rocksdb/EntrySet.java | 17 +-
.../org/dizitart/no2/rocksdb/RocksDBMap.java | 8 +-
.../rocksdb/formatter/NitriteSerializers.java | 20 +-
.../no2/rocksdb/NitriteBuilderTest.java | 6 +-
.../collection/CollectionIndexTest.java | 22 +-
.../repository/RepositoryFactoryTest.java | 4 +-
.../RepositoryModificationTest.java | 8 +-
.../no2/spatial/IntersectsFilter.java | 4 +-
.../dizitart/no2/spatial/SpatialIndexer.java | 4 +-
.../dizitart/no2/spatial/WithinFilter.java | 4 +-
.../no2/support/NitriteJsonExporter.java | 12 +-
.../no2/support/NitriteJsonImporter.java | 10 +-
.../support/ExporterImporterOptionTest.java | 4 +-
.../java/org/dizitart/no2/NitriteConfig.java | 21 +-
.../collection/DefaultNitriteCollection.java | 59 +--
.../no2/collection/DocumentCursor.java | 24 +-
.../no2/collection/NitriteCollection.java | 92 ++--
.../operation/BoundedDocumentStream.java | 4 +-
.../operation/CollectionOperations.java | 42 +-
.../operation/DocumentCursorImpl.java | 8 +-
.../operation/DocumentIndexWriter.java | 158 ++++++
.../no2/collection/operation/FindOptions.java | 21 +
.../collection/operation/IndexOperations.java | 279 ++++------
.../collection/operation/ReadOperations.java | 44 +-
.../operation/SortedDocumentCursor.java | 4 +-
.../collection/operation/StreamGenerator.java | 11 +
.../collection/operation/WriteOperations.java | 53 +-
.../common/{NullEntry.java => DBNull.java} | 10 +-
.../org/dizitart/no2/common/FieldValues.java | 46 ++
.../java/org/dizitart/no2/common/Fields.java | 127 +++++
.../no2/common/PersistentCollection.java | 226 +++++---
.../common/concurrent/ThreadPoolManager.java | 5 +-
.../no2/common/util/DocumentUtils.java | 17 +
.../dizitart/no2/common/util/Iterables.java | 19 +
.../dizitart/no2/common/util/StringUtils.java | 5 +
.../no2/common/util/ValidationUtils.java | 7 +
.../dizitart/no2/filters/EqualsFilter.java | 8 +-
.../no2/filters/GreaterEqualFilter.java | 4 +-
.../no2/filters/GreaterThanFilter.java | 4 +-
.../org/dizitart/no2/filters/InFilter.java | 4 +-
.../no2/filters/IndexAwareFilter.java | 4 +-
.../no2/filters/IndexedQuerySupport.java | 28 +
.../no2/filters/LesserEqualFilter.java | 4 +-
.../no2/filters/LesserThanFilter.java | 4 +-
.../dizitart/no2/filters/NotEqualsFilter.java | 8 +-
.../org/dizitart/no2/filters/NotInFilter.java | 4 +-
.../dizitart/no2/filters/QueryOptimizer.java | 61 +++
.../org/dizitart/no2/filters/TextFilter.java | 4 +-
.../no2/index/BaseNitriteIndexer.java | 62 +++
.../dizitart/no2/index/ComparableIndexer.java | 499 +++++++++++-------
.../{IndexEntry.java => IndexDescriptor.java} | 30 +-
.../org/dizitart/no2/index/IndexMeta.java | 6 +-
.../java/org/dizitart/no2/index/Indexer.java | 52 --
.../dizitart/no2/index/NitriteIndexer.java | 39 ++
.../no2/index/NitriteTextIndexer.java | 5 +-
.../org/dizitart/no2/index/TextIndexer.java | 2 +-
.../no2/migration/commands/AddField.java | 8 +-
.../migration/commands/ChangeDataType.java | 8 +-
.../no2/migration/commands/DeleteField.java | 6 +-
.../no2/migration/commands/Rename.java | 10 +-
.../no2/migration/commands/RenameField.java | 8 +-
.../dizitart/no2/module/PluginManager.java | 16 +-
.../repository/DefaultObjectRepository.java | 25 +-
.../no2/repository/ObjectRepository.java | 137 +++--
.../org/dizitart/no2/store/IndexCatalog.java | 73 +--
.../org/dizitart/no2/store/NitriteMap.java | 3 +
.../no2/store/memory/InMemoryMap.java | 72 +--
.../DefaultTransactionalCollection.java | 89 ++--
.../DefaultTransactionalRepository.java | 26 +-
.../no2/transaction/TransactionalConfig.java | 16 +-
.../no2/transaction/TransactionalMap.java | 94 ++--
...ntryTest.java => IndexDescriptorTest.java} | 12 +-
.../org/dizitart/no2/NitriteBuilderTest.java | 6 +-
.../no2/collection/CollectionIndexTest.java | 22 +-
.../no2/filters/EqualsFilterTest.java | 8 +-
.../no2/filters/NotEqualsFilterTest.java | 10 +-
.../dizitart/no2/filters/TextFilterTest.java | 2 +-
.../no2/index/IndexDescriptorTest.java | 28 +
.../dizitart/no2/index/IndexEntryTest.java | 28 -
.../no2/repository/RepositoryFactoryTest.java | 4 +-
.../RepositoryModificationTest.java | 8 +-
.../org/dizitart/no2/rx/FlowableCursor.java | 12 +-
.../no2/rx/FlowableDocumentCursor.java | 10 +-
...eStream.java => FlowableRecordStream.java} | 8 +-
.../no2/rx/RxNitriteCollectionImpl.java | 4 +-
.../no2/rx/RxObjectRepositoryImpl.java | 4 +-
.../no2/rx/RxPersistentCollection.java | 4 +-
103 files changed, 2014 insertions(+), 1225 deletions(-)
create mode 100644 nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/ReverseIterator.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentIndexWriter.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/collection/operation/FindOptions.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/collection/operation/StreamGenerator.java
rename nitrite/src/main/java/org/dizitart/no2/common/{NullEntry.java => DBNull.java} (54%)
create mode 100644 nitrite/src/main/java/org/dizitart/no2/common/FieldValues.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/common/Fields.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/filters/IndexedQuerySupport.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/filters/QueryOptimizer.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/index/BaseNitriteIndexer.java
rename nitrite/src/main/java/org/dizitart/no2/index/{IndexEntry.java => IndexDescriptor.java} (75%)
delete mode 100644 nitrite/src/main/java/org/dizitart/no2/index/Indexer.java
create mode 100644 nitrite/src/main/java/org/dizitart/no2/index/NitriteIndexer.java
rename nitrite/src/test/java/org/dizitart/no2/{IndexEntryTest.java => IndexDescriptorTest.java} (72%)
create mode 100644 nitrite/src/test/java/org/dizitart/no2/index/IndexDescriptorTest.java
delete mode 100644 nitrite/src/test/java/org/dizitart/no2/index/IndexEntryTest.java
rename rx-nitrite/src/main/java/org/dizitart/no2/rx/{FlowableReadableStream.java => FlowableRecordStream.java} (81%)
diff --git a/nitrite-android-example/build.gradle b/nitrite-android-example/build.gradle
index f7a99d5ff..63ceba59d 100644
--- a/nitrite-android-example/build.gradle
+++ b/nitrite-android-example/build.gradle
@@ -46,8 +46,7 @@ android {
exclude 'META-INF/LGPL2.1'
}
- compileSdkVersion 28
-
+ compileSdkVersion 29
defaultConfig {
applicationId "org.dizitart.no2.example.android"
@@ -56,8 +55,9 @@ android {
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+// multiDexEnabled true
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -72,6 +72,7 @@ android {
}
compileOptions {
+// coreLibraryDesugaringEnabled true
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
@@ -92,6 +93,8 @@ dependencies {
implementation 'com.android.support:design:28.0.0'
annotationProcessor "org.projectlombok:lombok:1.18.12"
+// coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
+
testImplementation 'junit:junit:4.13'
testAnnotationProcessor "org.projectlombok:lombok:1.18.12"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
diff --git a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/test/RepositoryModificationTest.java b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/test/RepositoryModificationTest.java
index d9f8b9668..b607e7f5b 100644
--- a/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/test/RepositoryModificationTest.java
+++ b/nitrite-jackson-mapper/src/test/java/org/dizitart/no2/test/RepositoryModificationTest.java
@@ -21,7 +21,7 @@
import org.dizitart.no2.exceptions.InvalidIdException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.repository.Cursor;
@@ -69,7 +69,7 @@ public void testRebuildIndex() {
@Test
public void testListIndexes() {
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
companyRepository.createIndex("dateCreated", IndexOptions.indexOptions(IndexType.NonUnique));
@@ -81,7 +81,7 @@ public void testListIndexes() {
public void testDropIndex() {
testListIndexes();
companyRepository.dropIndex("dateCreated");
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
}
@@ -89,7 +89,7 @@ public void testDropIndex() {
public void testDropAllIndex() {
testListIndexes();
companyRepository.dropAllIndices();
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 0);
}
diff --git a/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBMap.java b/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBMap.java
index 7eabe6740..27635a93a 100644
--- a/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBMap.java
+++ b/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBMap.java
@@ -3,7 +3,7 @@
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
-import org.dizitart.no2.common.NullEntry;
+import org.dizitart.no2.common.DBNull;
import org.dizitart.no2.common.RecordStream;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.exceptions.NitriteIOException;
@@ -14,6 +14,7 @@
import java.util.Iterator;
import java.util.Map;
+import java.util.NavigableMap;
import static org.dizitart.no2.common.util.ValidationUtils.notNull;
@@ -26,14 +27,14 @@ public class MapDBMap implements NitriteMap {
private final BTreeMap bTreeMap;
@Getter(AccessLevel.PACKAGE)
- private final BTreeMap nullEntryMap;
+ private final BTreeMap nullEntryMap;
private final NitriteStore> nitriteStore;
private final String mapName;
public MapDBMap(String mapName, BTreeMap bTreeMap,
- BTreeMap nullEntryMap, NitriteStore> nitriteStore) {
+ BTreeMap nullEntryMap, NitriteStore> nitriteStore) {
this.bTreeMap = bTreeMap;
this.mapName = mapName;
this.nitriteStore = nitriteStore;
@@ -43,7 +44,7 @@ public MapDBMap(String mapName, BTreeMap bTreeMap,
@Override
public boolean containsKey(K k) {
if (k == null) {
- return nullEntryMap.containsKey(NullEntry.getInstance());
+ return nullEntryMap.containsKey(DBNull.getInstance());
}
return bTreeMap.containsKey(k);
}
@@ -51,7 +52,7 @@ public boolean containsKey(K k) {
@Override
public V get(K k) {
if (k == null) {
- return nullEntryMap.get(NullEntry.getInstance());
+ return nullEntryMap.get(DBNull.getInstance());
}
Map.Entry firstEntry = bTreeMap.firstEntry();
@@ -90,7 +91,7 @@ public RecordStream values() {
public V remove(K k) {
V value;
if (k == null) {
- value = nullEntryMap.remove(NullEntry.getInstance());
+ value = nullEntryMap.remove(DBNull.getInstance());
} else {
value = bTreeMap.remove(k);
}
@@ -102,7 +103,7 @@ public V remove(K k) {
public RecordStream keySet() {
return RecordStream.fromIterable(() -> new Iterator() {
final Iterator keyIterator = bTreeMap.keyIterator();
- final Iterator nullEntryIterator = nullEntryMap.keyIterator();
+ final Iterator nullEntryIterator = nullEntryMap.keyIterator();
@Override
public boolean hasNext() {
@@ -129,7 +130,7 @@ public void put(K k, V v) {
notNull(v, "value cannot be null");
try {
if (k == null) {
- nullEntryMap.put(NullEntry.getInstance(), v);
+ nullEntryMap.put(DBNull.getInstance(), v);
} else {
Map.Entry firstEntry = bTreeMap.firstEntry();
if (firstEntry != null) {
@@ -157,7 +158,7 @@ public V putIfAbsent(K k, V v) {
V value;
if (k == null) {
- value = nullEntryMap.putIfAbsent(NullEntry.getInstance(), v);
+ value = nullEntryMap.putIfAbsent(DBNull.getInstance(), v);
} else {
value = bTreeMap.putIfAbsent(k, v);
}
@@ -167,30 +168,12 @@ public V putIfAbsent(K k, V v) {
@Override
public RecordStream> entries() {
- return () -> new Iterator>() {
- final Iterator> entryIterator = bTreeMap.entrySet().iterator();
- final Iterator> nullEntryIterator = nullEntryMap.entrySet().iterator();
-
- @Override
- public boolean hasNext() {
- boolean result = nullEntryIterator.hasNext();
- if (!result) {
- return entryIterator.hasNext();
- }
- return true;
- }
+ return getStream(bTreeMap, nullEntryMap);
+ }
- @Override
- public Pair next() {
- if (nullEntryIterator.hasNext()) {
- Map.Entry entry = nullEntryIterator.next();
- return new Pair<>(null, entry.getValue());
- } else {
- Map.Entry entry = entryIterator.next();
- return new Pair<>(entry.getKey(), entry.getValue());
- }
- }
- };
+ @Override
+ public RecordStream> reversedEntries() {
+ return getStream(bTreeMap.descendingMap(), nullEntryMap.descendingMap());
}
@Override
@@ -240,4 +223,34 @@ public void close() {
bTreeMap.close();
nullEntryMap.close();
}
+
+ private RecordStream> getStream(NavigableMap primaryMap,
+ NavigableMap nullEntryMap) {
+ return RecordStream.fromIterable(() -> new Iterator>() {
+ private final Iterator> entryIterator =
+ primaryMap.entrySet().iterator();
+ private final Iterator> nullEntryIterator =
+ nullEntryMap.entrySet().iterator();
+
+ @Override
+ public boolean hasNext() {
+ boolean result = nullEntryIterator.hasNext();
+ if (!result) {
+ return entryIterator.hasNext();
+ }
+ return true;
+ }
+
+ @Override
+ public Pair next() {
+ if (nullEntryIterator.hasNext()) {
+ Map.Entry entry = nullEntryIterator.next();
+ return new Pair<>(null, entry.getValue());
+ } else {
+ Map.Entry entry = entryIterator.next();
+ return new Pair<>(entry.getKey(), entry.getValue());
+ }
+ }
+ });
+ }
}
diff --git a/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBStore.java b/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBStore.java
index 22ba080d2..85c579539 100644
--- a/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBStore.java
+++ b/nitrite-mapdb-adapter/src/main/java/org/dizitart/no2/mapdb/MapDBStore.java
@@ -1,7 +1,7 @@
package org.dizitart.no2.mapdb;
import lombok.extern.slf4j.Slf4j;
-import org.dizitart.no2.common.NullEntry;
+import org.dizitart.no2.common.DBNull;
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.index.BoundingBox;
import org.dizitart.no2.mapdb.serializers.Serializers;
@@ -94,7 +94,7 @@ public NitriteMap openMap(String mapName, Class> keyT
BTreeMap bTreeMap = treeMapMaker.createOrOpen();
// mapdb btreemap does not support null key, so all null key entries are maintained in a separate map
- DB.TreeMapMaker nullMapMaker = (DB.TreeMapMaker) db
+ DB.TreeMapMaker nullMapMaker = (DB.TreeMapMaker) db
.treeMap(mapName + "null-map")
.counterEnable()
.valuesOutsideNodesEnable();
@@ -103,7 +103,7 @@ public NitriteMap openMap(String mapName, Class> keyT
nullMapMaker.valueSerializer(valueSerializer);
}
- BTreeMap nullMap = nullMapMaker.createOrOpen();
+ BTreeMap nullMap = nullMapMaker.createOrOpen();
MapDBMap mapDBMap = new MapDBMap<>(mapName, bTreeMap, nullMap, this);
nitriteMapRegistry.put(mapName, mapDBMap);
diff --git a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/NitriteBuilderTest.java b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/NitriteBuilderTest.java
index 26d80df47..dbc63bd74 100644
--- a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/NitriteBuilderTest.java
+++ b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/NitriteBuilderTest.java
@@ -25,7 +25,7 @@
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.exceptions.NitriteIOException;
import org.dizitart.no2.exceptions.SecurityException;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.mapper.Mappable;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.repository.ObjectRepository;
@@ -307,7 +307,7 @@ public void testInvalidPath() {
assertNull(db);
}
- private static class CustomIndexer implements Indexer {
+ private static class CustomIndexer implements NitriteIndexer {
@Override
public String getIndexType() {
@@ -335,7 +335,7 @@ public void dropIndex(NitriteMap collection, String field)
}
@Override
- public Indexer clone() throws CloneNotSupportedException {
+ public NitriteIndexer clone() throws CloneNotSupportedException {
return null;
}
diff --git a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/collection/CollectionIndexTest.java b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/collection/CollectionIndexTest.java
index 4a56c3cff..8727f6c85 100644
--- a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/collection/CollectionIndexTest.java
+++ b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/collection/CollectionIndexTest.java
@@ -23,7 +23,7 @@
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.mapdb.BaseCollectionTest;
import org.junit.Test;
@@ -140,9 +140,9 @@ public void testCreateIndexAsync() {
public void testRebuildIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
insert();
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), false);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), false);
}
}
@@ -152,9 +152,9 @@ public void testRebuildIndexAsync() {
insert();
await().until(bodyIndexingCompleted());
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), true);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), true);
await().until(bodyIndexingCompleted());
}
}
@@ -162,14 +162,14 @@ public void testRebuildIndexAsync() {
@Test
public void testRebuildIndexOnRunningIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
- Collection indices = collection.listIndices();
- IndexEntry idx = indices.iterator().next();
+ Collection indices = collection.listIndices();
+ IndexDescriptor idx = indices.iterator().next();
insert();
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
boolean error = false;
try {
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
} catch (IndexingException ie) {
error = true;
} finally {
diff --git a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryFactoryTest.java b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryFactoryTest.java
index 859a822d6..25e4821dc 100644
--- a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryFactoryTest.java
+++ b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryFactoryTest.java
@@ -24,7 +24,7 @@
import org.dizitart.no2.common.concurrent.LockService;
import org.dizitart.no2.exceptions.ValidationException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.mapdb.Retry;
import org.dizitart.no2.mapdb.TestUtil;
@@ -123,7 +123,7 @@ public void rebuildIndex(String field, boolean isAsync) {
}
@Override
- public Collection listIndices() {
+ public Collection listIndices() {
return null;
}
diff --git a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryModificationTest.java b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryModificationTest.java
index 0cd95fba9..023f1269b 100644
--- a/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryModificationTest.java
+++ b/nitrite-mapdb-adapter/src/test/java/org/dizitart/no2/mapdb/repository/RepositoryModificationTest.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.exceptions.InvalidIdException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.mapdb.repository.data.*;
@@ -70,7 +70,7 @@ public void testRebuildIndex() {
@Test
public void testListIndexes() {
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
companyRepository.createIndex("dateCreated", IndexOptions.indexOptions(IndexType.NonUnique));
@@ -82,7 +82,7 @@ public void testListIndexes() {
public void testDropIndex() {
testListIndexes();
companyRepository.dropIndex("dateCreated");
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
}
@@ -90,7 +90,7 @@ public void testDropIndex() {
public void testDropAllIndex() {
testListIndexes();
companyRepository.dropAllIndices();
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 0);
}
diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVMap.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVMap.java
index 6e56eb5aa..5dc1dac1c 100644
--- a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVMap.java
+++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVMap.java
@@ -121,6 +121,11 @@ public Pair next() {
};
}
+ @Override
+ public RecordStream> reversedEntries() {
+ return () -> new ReverseIterator<>(mvMap);
+ }
+
@Override
public Key higherKey(Key key) {
return mvMap.higherKey(key);
diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/ReverseIterator.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/ReverseIterator.java
new file mode 100644
index 000000000..f98c0fae0
--- /dev/null
+++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/ReverseIterator.java
@@ -0,0 +1,42 @@
+package org.dizitart.no2.mvstore;
+
+import org.dizitart.no2.common.tuples.Pair;
+import org.h2.mvstore.MVMap;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * @author Anindya Chatterjee
+ */
+public class ReverseIterator implements Iterator> {
+ private final MVMap mvMap;
+ private Key anchor;
+ private boolean started;
+
+ public ReverseIterator(MVMap mvMap) {
+ long version = mvMap.getVersion();
+ this.mvMap = mvMap.openVersion(version);
+ this.anchor = this.mvMap.lastKey();
+ this.started = false;
+ }
+
+ @Override
+ public boolean hasNext() {
+ Key key = started ? mvMap.lowerKey(this.anchor) : mvMap.floorKey(this.anchor);
+ return key != null;
+ }
+
+ @Override
+ public Pair next() {
+ Key key = started ? mvMap.lowerKey(this.anchor) : mvMap.floorKey(this.anchor);
+ this.started = true;
+ if (key == null) {
+ throw new NoSuchElementException();
+ }
+
+ Value value = mvMap.get(key);
+ this.anchor = key;
+ return new Pair<>(key, value);
+ }
+}
diff --git a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v3/MigrationUtil.java b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v3/MigrationUtil.java
index 138c8888c..240785237 100644
--- a/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v3/MigrationUtil.java
+++ b/nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/compat/v3/MigrationUtil.java
@@ -21,7 +21,7 @@
import org.dizitart.no2.collection.meta.Attributes;
import org.dizitart.no2.exceptions.NitriteIOException;
import org.dizitart.no2.exceptions.ValidationException;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexMeta;
import org.dizitart.no2.store.UserCredential;
import org.h2.mvstore.MVMap;
@@ -175,19 +175,19 @@ private static Document document(Compat.Document value) {
private static IndexMeta indexMeta(Compat.IndexMeta value) {
Compat.Index index = value.getIndex();
- IndexEntry indexEntry = indexEntry(index);
+ IndexDescriptor indexDescriptor = indexEntry(index);
IndexMeta indexMeta = new IndexMeta();
- indexMeta.setIndexEntry(indexEntry);
+ indexMeta.setIndexDescriptor(indexDescriptor);
indexMeta.setIndexMap(value.getIndexMap());
indexMeta.setIsDirty(value.getIsDirty());
return indexMeta;
}
- private static IndexEntry indexEntry(Compat.Index value) {
+ private static IndexDescriptor indexEntry(Compat.Index value) {
String indexType = value.getIndexType().name();
- return new IndexEntry(indexType, value.getField(), value.getCollectionName());
+ return new IndexDescriptor(indexType, value.getField(), value.getCollectionName());
}
private static NitriteId nitriteId(Compat.NitriteId value) {
diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteBuilderTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteBuilderTest.java
index eabd8d511..a27e3dbb8 100644
--- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteBuilderTest.java
+++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/NitriteBuilderTest.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.exceptions.NitriteIOException;
import org.dizitart.no2.exceptions.SecurityException;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.mapper.Mappable;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.mvstore.MVStoreConfig;
@@ -315,7 +315,7 @@ public void testInvalidPath() {
assertNull(db);
}
- private static class CustomIndexer implements Indexer {
+ private static class CustomIndexer implements NitriteIndexer {
@Override
public String getIndexType() {
@@ -343,7 +343,7 @@ public void dropIndex(NitriteMap collection, String field)
}
@Override
- public Indexer clone() throws CloneNotSupportedException {
+ public NitriteIndexer clone() throws CloneNotSupportedException {
return null;
}
diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/collection/CollectionIndexTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/collection/CollectionIndexTest.java
index 161e52626..1a9bdb9ab 100644
--- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/collection/CollectionIndexTest.java
+++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/collection/CollectionIndexTest.java
@@ -19,7 +19,7 @@
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexType;
import org.junit.Test;
@@ -136,9 +136,9 @@ public void testCreateIndexAsync() {
public void testRebuildIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
insert();
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), false);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), false);
}
}
@@ -148,9 +148,9 @@ public void testRebuildIndexAsync() {
insert();
await().until(bodyIndexingCompleted());
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), true);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), true);
await().until(bodyIndexingCompleted());
}
}
@@ -158,14 +158,14 @@ public void testRebuildIndexAsync() {
@Test
public void testRebuildIndexOnRunningIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
- Collection indices = collection.listIndices();
- IndexEntry idx = indices.iterator().next();
+ Collection indices = collection.listIndices();
+ IndexDescriptor idx = indices.iterator().next();
insert();
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
boolean error = false;
try {
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
} catch (IndexingException ie) {
error = true;
} finally {
diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryFactoryTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryFactoryTest.java
index e012507f7..7612946b0 100644
--- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryFactoryTest.java
+++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryFactoryTest.java
@@ -26,7 +26,7 @@
import org.dizitart.no2.common.concurrent.LockService;
import org.dizitart.no2.exceptions.ValidationException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.store.NitriteStore;
import org.junit.After;
@@ -122,7 +122,7 @@ public void rebuildIndex(String field, boolean isAsync) {
}
@Override
- public Collection listIndices() {
+ public Collection listIndices() {
return null;
}
diff --git a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryModificationTest.java b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryModificationTest.java
index 7c0813651..3c259a8a8 100644
--- a/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryModificationTest.java
+++ b/nitrite-mvstore-adapter/src/test/java/org/dizitart/no2/repository/RepositoryModificationTest.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.exceptions.InvalidIdException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.repository.data.*;
@@ -68,7 +68,7 @@ public void testRebuildIndex() {
@Test
public void testListIndexes() {
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
companyRepository.createIndex("dateCreated", IndexOptions.indexOptions(IndexType.NonUnique));
@@ -80,7 +80,7 @@ public void testListIndexes() {
public void testDropIndex() {
testListIndexes();
companyRepository.dropIndex("dateCreated");
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
}
@@ -88,7 +88,7 @@ public void testDropIndex() {
public void testDropAllIndex() {
testListIndexes();
companyRepository.dropAllIndices();
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 0);
}
diff --git a/nitrite-replication/src/main/java/org/dizitart/no2/sync/ReplicationTemplate.java b/nitrite-replication/src/main/java/org/dizitart/no2/sync/ReplicationTemplate.java
index 53ecd7f00..1338f1e4b 100644
--- a/nitrite-replication/src/main/java/org/dizitart/no2/sync/ReplicationTemplate.java
+++ b/nitrite-replication/src/main/java/org/dizitart/no2/sync/ReplicationTemplate.java
@@ -76,7 +76,7 @@ public class ReplicationTemplate implements ReplicationOperation {
public ReplicationTemplate(Config config) {
this.config = config;
- init();
+ initialize();
}
public void connect() {
@@ -186,7 +186,7 @@ public void collectGarbage(Long ttl) {
}
}
- private void init() {
+ private void initialize() {
this.messageFactory = new MessageFactory();
this.connected = new AtomicBoolean(false);
this.exchangeFlag = new AtomicBoolean(false);
diff --git a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/EntrySet.java b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/EntrySet.java
index 68fe5abb1..43ce9f1e5 100644
--- a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/EntrySet.java
+++ b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/EntrySet.java
@@ -12,14 +12,17 @@ class EntrySet implements Iterable> {
private final ColumnFamilyHandle columnFamilyHandle;
private final Class> keyType;
private final Class> valueType;
+ private final boolean reverse;
public EntrySet(RocksDB rocksDB, ColumnFamilyHandle columnFamilyHandle,
- ObjectFormatter objectFormatter, Class> keyType, Class> valueType) {
+ ObjectFormatter objectFormatter, Class> keyType,
+ Class> valueType, boolean reverse) {
this.rocksDB = rocksDB;
this.columnFamilyHandle = columnFamilyHandle;
this.objectFormatter = objectFormatter;
this.keyType = keyType;
this.valueType = valueType;
+ this.reverse = reverse;
}
@Override
@@ -33,7 +36,11 @@ private class EntryIterator implements Iterator> {
public EntryIterator() {
rawEntryIterator = rocksDB.newIterator(columnFamilyHandle);
- rawEntryIterator.seekToFirst();
+ if (reverse) {
+ rawEntryIterator.seekToLast();
+ } else {
+ rawEntryIterator.seekToFirst();
+ }
}
@Override
@@ -55,7 +62,11 @@ public Pair next() {
K key = (K) objectFormatter.decodeKey(rawEntryIterator.key(), keyType);
try {
V value = (V) objectFormatter.decode(rawEntryIterator.value(), valueType);
- rawEntryIterator.next();
+ if (reverse) {
+ rawEntryIterator.prev();
+ } else {
+ rawEntryIterator.next();
+ }
return new Pair<>(key, value);
} catch (Exception e) {
System.out.println(new String(rawEntryIterator.value()));
diff --git a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/RocksDBMap.java b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/RocksDBMap.java
index 37870e88d..da4fc9675 100644
--- a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/RocksDBMap.java
+++ b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/RocksDBMap.java
@@ -208,7 +208,13 @@ public V putIfAbsent(K k, V v) {
@Override
public RecordStream> entries() {
return RecordStream.fromIterable(new EntrySet<>(rocksDB, columnFamilyHandle,
- objectFormatter, getKeyType(), getValueType()));
+ objectFormatter, getKeyType(), getValueType(), false));
+ }
+
+ @Override
+ public RecordStream> reversedEntries() {
+ return RecordStream.fromIterable(new EntrySet<>(rocksDB, columnFamilyHandle,
+ objectFormatter, getKeyType(), getValueType(), true));
}
@Override
diff --git a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/formatter/NitriteSerializers.java b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/formatter/NitriteSerializers.java
index 98146e61c..226d3d396 100644
--- a/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/formatter/NitriteSerializers.java
+++ b/nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/formatter/NitriteSerializers.java
@@ -9,7 +9,7 @@
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.collection.meta.Attributes;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexMeta;
import org.dizitart.no2.store.UserCredential;
@@ -87,39 +87,39 @@ private static class IndexMetaSerializer extends Serializer {
@Override
public void write(Kryo kryo, Output output, IndexMeta object) {
- kryo.writeObject(output, object.getIndexEntry());
+ kryo.writeObject(output, object.getIndexDescriptor());
output.writeString(object.getIndexMap());
output.writeBoolean(object.getIsDirty().get());
}
@Override
public IndexMeta read(Kryo kryo, Input input, Class type) {
- IndexEntry indexEntry = kryo.readObject(input, IndexEntry.class);
+ IndexDescriptor indexDescriptor = kryo.readObject(input, IndexDescriptor.class);
String indexMap = input.readString();
boolean isDirty = input.readBoolean();
IndexMeta indexMeta = new IndexMeta();
- indexMeta.setIndexEntry(indexEntry);
+ indexMeta.setIndexDescriptor(indexDescriptor);
indexMeta.setIndexMap(indexMap);
indexMeta.setIsDirty(new AtomicBoolean(isDirty));
return indexMeta;
}
}
- private static class IndexEntrySerializer extends Serializer {
+ private static class IndexEntrySerializer extends Serializer {
@Override
- public void write(Kryo kryo, Output output, IndexEntry object) {
+ public void write(Kryo kryo, Output output, IndexDescriptor object) {
output.writeString(object.getCollectionName());
- output.writeString(object.getField());
+ output.writeString(object.getFields());
output.writeString(object.getIndexType());
}
@Override
- public IndexEntry read(Kryo kryo, Input input, Class type) {
+ public IndexDescriptor read(Kryo kryo, Input input, Class type) {
String collectionName = input.readString();
String field = input.readString();
String indexType = input.readString();
- return new IndexEntry(indexType, field, collectionName);
+ return new IndexDescriptor(indexType, field, collectionName);
}
}
@@ -171,7 +171,7 @@ public static void registerAll(KryoObjectFormatter kryoObjectFormatter) {
kryoObjectFormatter.registerSerializer(Pair.class, new PairSerializer());
kryoObjectFormatter.registerSerializer(Document.class, new DocumentSerializer());
kryoObjectFormatter.registerSerializer(IndexMeta.class, new IndexMetaSerializer());
- kryoObjectFormatter.registerSerializer(IndexEntry.class, new IndexEntrySerializer());
+ kryoObjectFormatter.registerSerializer(IndexDescriptor.class, new IndexEntrySerializer());
kryoObjectFormatter.registerSerializer(UserCredential.class, new UserCredentialSerializer());
kryoObjectFormatter.registerSerializer(Attributes.class, new AttributesSerializer());
}
diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/NitriteBuilderTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/NitriteBuilderTest.java
index 895048181..f2f29da6c 100644
--- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/NitriteBuilderTest.java
+++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/NitriteBuilderTest.java
@@ -26,7 +26,7 @@
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.exceptions.NitriteIOException;
import org.dizitart.no2.exceptions.SecurityException;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.mapper.Mappable;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.repository.ObjectRepository;
@@ -256,7 +256,7 @@ public void testFieldSeparator() {
assertEquals(document.get("colorCodes::1::color"), "Green");
}
- private static class CustomIndexer implements Indexer {
+ private static class CustomIndexer implements NitriteIndexer {
@Override
public String getIndexType() {
@@ -284,7 +284,7 @@ public void dropIndex(NitriteMap collection, String field)
}
@Override
- public Indexer clone() throws CloneNotSupportedException {
+ public NitriteIndexer clone() throws CloneNotSupportedException {
return null;
}
diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/collection/CollectionIndexTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/collection/CollectionIndexTest.java
index 59c46cfeb..d56218dea 100644
--- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/collection/CollectionIndexTest.java
+++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/collection/CollectionIndexTest.java
@@ -23,7 +23,7 @@
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.rocksdb.BaseCollectionTest;
import org.junit.Test;
@@ -140,9 +140,9 @@ public void testCreateIndexAsync() {
public void testRebuildIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
insert();
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), false);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), false);
}
}
@@ -152,9 +152,9 @@ public void testRebuildIndexAsync() {
insert();
await().until(bodyIndexingCompleted());
- Collection indices = collection.listIndices();
- for (IndexEntry idx : indices) {
- collection.rebuildIndex(idx.getField(), true);
+ Collection indices = collection.listIndices();
+ for (IndexDescriptor idx : indices) {
+ collection.rebuildIndex(idx.getFields(), true);
await().until(bodyIndexingCompleted());
}
}
@@ -162,14 +162,14 @@ public void testRebuildIndexAsync() {
@Test
public void testRebuildIndexOnRunningIndex() {
collection.createIndex("body", indexOptions(IndexType.Fulltext, false));
- Collection indices = collection.listIndices();
- IndexEntry idx = indices.iterator().next();
+ Collection indices = collection.listIndices();
+ IndexDescriptor idx = indices.iterator().next();
insert();
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
boolean error = false;
try {
- collection.rebuildIndex(idx.getField(), true);
+ collection.rebuildIndex(idx.getFields(), true);
} catch (IndexingException ie) {
error = true;
} finally {
diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryFactoryTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryFactoryTest.java
index 693884346..64540be80 100644
--- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryFactoryTest.java
+++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryFactoryTest.java
@@ -24,7 +24,7 @@
import org.dizitart.no2.common.concurrent.LockService;
import org.dizitart.no2.exceptions.ValidationException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.repository.RepositoryFactory;
import org.dizitart.no2.rocksdb.DbTestOperations;
@@ -127,7 +127,7 @@ public void rebuildIndex(String field, boolean isAsync) {
}
@Override
- public Collection listIndices() {
+ public Collection listIndices() {
return null;
}
diff --git a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryModificationTest.java b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryModificationTest.java
index 53b047a44..723d6f0ef 100644
--- a/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryModificationTest.java
+++ b/nitrite-rocksdb-adapter/src/test/java/org/dizitart/no2/rocksdb/repository/RepositoryModificationTest.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.exceptions.InvalidIdException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.rocksdb.repository.data.*;
@@ -70,7 +70,7 @@ public void testRebuildIndex() {
@Test
public void testListIndexes() {
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
companyRepository.createIndex("dateCreated", IndexOptions.indexOptions(IndexType.NonUnique));
@@ -82,7 +82,7 @@ public void testListIndexes() {
public void testDropIndex() {
testListIndexes();
companyRepository.dropIndex("dateCreated");
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 2);
}
@@ -90,7 +90,7 @@ public void testDropIndex() {
public void testDropAllIndex() {
testListIndexes();
companyRepository.dropAllIndices();
- Collection indices = companyRepository.listIndices();
+ Collection indices = companyRepository.listIndices();
assertEquals(indices.size(), 0);
}
diff --git a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/IntersectsFilter.java b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/IntersectsFilter.java
index d20f7b6a0..2b5ab8574 100644
--- a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/IntersectsFilter.java
+++ b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/IntersectsFilter.java
@@ -35,8 +35,8 @@ protected IntersectsFilter(String field, Geometry geometry) {
@Override
protected Set findIndexedIdSet() {
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof SpatialIndexer && getValue() != null) {
- SpatialIndexer spatialIndexer = (SpatialIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof SpatialIndexer && getValue() != null) {
+ SpatialIndexer spatialIndexer = (SpatialIndexer) getNitriteIndexer();
RecordStream idSet = spatialIndexer.findIntersects(getCollectionName(), getField(), getValue());
return idSet.toSet();
} else {
diff --git a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/SpatialIndexer.java b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/SpatialIndexer.java
index fe26b59eb..5cf5641c7 100644
--- a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/SpatialIndexer.java
+++ b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/SpatialIndexer.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.common.RecordStream;
import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.index.BoundingBox;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.store.NitriteMap;
import org.dizitart.no2.store.NitriteRTree;
@@ -33,7 +33,7 @@
* @author Anindya Chatterjee
* @since 4.0.0
*/
-public class SpatialIndexer implements Indexer {
+public class SpatialIndexer implements NitriteIndexer {
public static final String SpatialIndex = "Spatial";
private NitriteMapper nitriteMapper;
diff --git a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/WithinFilter.java b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/WithinFilter.java
index 842043496..7afe310f7 100644
--- a/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/WithinFilter.java
+++ b/nitrite-spatial/src/main/java/org/dizitart/no2/spatial/WithinFilter.java
@@ -35,8 +35,8 @@ protected WithinFilter(String field, Geometry geometry) {
@Override
protected Set findIndexedIdSet() {
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof SpatialIndexer && getValue() != null) {
- SpatialIndexer spatialIndexer = (SpatialIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof SpatialIndexer && getValue() != null) {
+ SpatialIndexer spatialIndexer = (SpatialIndexer) getNitriteIndexer();
RecordStream idSet = spatialIndexer.findWithin(getCollectionName(), getField(), getValue());
return idSet.toSet();
} else {
diff --git a/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonExporter.java b/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonExporter.java
index 67dec708e..cb2fcff73 100644
--- a/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonExporter.java
+++ b/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonExporter.java
@@ -24,7 +24,7 @@
import org.dizitart.no2.collection.NitriteCollection;
import org.dizitart.no2.common.PersistentCollection;
import org.dizitart.no2.exceptions.NitriteIOException;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.repository.ObjectRepository;
import java.io.ByteArrayOutputStream;
@@ -139,7 +139,7 @@ private void writeRepository(ObjectRepository> repository) throws IOException
generator.writeFieldName(TAG_TYPE);
generator.writeString(repository.getType().getName());
- Collection indices = repository.listIndices();
+ Collection indices = repository.listIndices();
writeIndices(indices);
DocumentCursor cursor = repository.getDocumentCollection().find();
@@ -156,7 +156,7 @@ private void writeKeyedRepository(String key, ObjectRepository> repository) th
generator.writeFieldName(TAG_TYPE);
generator.writeString(repository.getType().getName());
- Collection indices = repository.listIndices();
+ Collection indices = repository.listIndices();
writeIndices(indices);
DocumentCursor cursor = repository.getDocumentCollection().find();
@@ -169,7 +169,7 @@ private void writeCollection(NitriteCollection nitriteCollection) throws IOExcep
generator.writeFieldName(TAG_NAME);
generator.writeString(nitriteCollection.getName());
- Collection indices = nitriteCollection.listIndices();
+ Collection indices = nitriteCollection.listIndices();
writeIndices(indices);
DocumentCursor cursor = nitriteCollection.find();
@@ -177,11 +177,11 @@ private void writeCollection(NitriteCollection nitriteCollection) throws IOExcep
generator.writeEndObject();
}
- private void writeIndices(Collection indices) throws IOException {
+ private void writeIndices(Collection indices) throws IOException {
generator.writeFieldName(TAG_INDICES);
generator.writeStartArray();
if (options.isExportIndices()) {
- for (IndexEntry index : indices) {
+ for (IndexDescriptor index : indices) {
generator.writeStartObject();
generator.writeFieldName(TAG_INDEX);
generator.writeObject(writeEncodedObject(index));
diff --git a/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonImporter.java b/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonImporter.java
index 2c72576f0..76882c677 100644
--- a/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonImporter.java
+++ b/nitrite-support/src/main/java/org/dizitart/no2/support/NitriteJsonImporter.java
@@ -24,7 +24,7 @@
import org.dizitart.no2.collection.NitriteCollection;
import org.dizitart.no2.common.PersistentCollection;
import org.dizitart.no2.exceptions.NitriteIOException;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.repository.ObjectRepository;
@@ -179,11 +179,11 @@ private void readIndices(PersistentCollection> collection) throws IOException
if (TAG_INDEX.equals(fieldName)) {
parser.nextToken();
String data = parser.readValueAs(String.class);
- IndexEntry index = (IndexEntry) readEncodedObject(data);
+ IndexDescriptor index = (IndexDescriptor) readEncodedObject(data);
if (collection != null && index != null
- && index.getField() != null
- && !collection.hasIndex(index.getField())) {
- collection.createIndex(index.getField(),
+ && index.getFields() != null
+ && !collection.hasIndex(index.getFields())) {
+ collection.createIndex(index.getFields(),
IndexOptions.indexOptions(index.getIndexType()));
}
}
diff --git a/nitrite-support/src/test/java/org/dizitart/no2/support/ExporterImporterOptionTest.java b/nitrite-support/src/test/java/org/dizitart/no2/support/ExporterImporterOptionTest.java
index f7b868910..1523eff59 100644
--- a/nitrite-support/src/test/java/org/dizitart/no2/support/ExporterImporterOptionTest.java
+++ b/nitrite-support/src/test/java/org/dizitart/no2/support/ExporterImporterOptionTest.java
@@ -19,7 +19,7 @@
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteCollection;
import org.dizitart.no2.common.PersistentCollection;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.repository.ObjectRepository;
import org.junit.Test;
@@ -87,6 +87,6 @@ public void testImportExportSingle() {
new ArrayList());
assertEquals(destCompRepo.listIndices(), sourceCompRepo.listIndices());
- assertEquals(destSecondColl.listIndices(), new LinkedHashSet());
+ assertEquals(destSecondColl.listIndices(), new LinkedHashSet());
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java b/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java
index 225470598..4ee8d82d7 100644
--- a/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java
+++ b/nitrite/src/main/java/org/dizitart/no2/NitriteConfig.java
@@ -21,8 +21,9 @@
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.dizitart.no2.common.Constants;
+import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.exceptions.InvalidOperationException;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.migration.Migration;
import org.dizitart.no2.module.NitriteModule;
@@ -144,15 +145,19 @@ public void autoConfigure() {
}
/**
- * Finds an {@link Indexer} by indexType.
+ * Finds an {@link NitriteIndexer} by indexType.
*
- * @param indexType the type of {@link Indexer} to find.
- * @return the {@link Indexer}
+ * @param indexType the type of {@link NitriteIndexer} to find.
+ * @return the {@link NitriteIndexer}
*/
- public Indexer findIndexer(String indexType) {
- Indexer indexer = pluginManager.getIndexerMap().get(indexType);
- indexer.initialize(this);
- return indexer;
+ public NitriteIndexer findIndexer(String indexType) {
+ NitriteIndexer nitriteIndexer = pluginManager.getIndexerMap().get(indexType);
+ if (nitriteIndexer != null) {
+ nitriteIndexer.initialize(this);
+ return nitriteIndexer;
+ } else {
+ throw new IndexingException("no indexer found for index type " + indexType);
+ }
}
/**
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/DefaultNitriteCollection.java b/nitrite/src/main/java/org/dizitart/no2/collection/DefaultNitriteCollection.java
index 9ffa2944f..5392c5ab0 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/DefaultNitriteCollection.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/DefaultNitriteCollection.java
@@ -22,6 +22,7 @@
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.meta.Attributes;
import org.dizitart.no2.collection.operation.CollectionOperations;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.common.concurrent.LockService;
import org.dizitart.no2.common.event.EventBus;
@@ -31,7 +32,7 @@
import org.dizitart.no2.exceptions.NitriteIOException;
import org.dizitart.no2.exceptions.NotIdentifiableException;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.store.NitriteMap;
@@ -42,8 +43,7 @@
import static org.dizitart.no2.collection.UpdateOptions.updateOptions;
import static org.dizitart.no2.common.util.DocumentUtils.createUniqueFilter;
-import static org.dizitart.no2.common.util.ValidationUtils.containsNull;
-import static org.dizitart.no2.common.util.ValidationUtils.notNull;
+import static org.dizitart.no2.common.util.ValidationUtils.*;
/**
* @author Anindya Chatterjee.
@@ -167,7 +167,6 @@ public DocumentCursor find() {
public DocumentCursor find(Filter filter) {
checkOpened();
-
try {
readLock.lock();
return collectionOperations.find(filter);
@@ -176,17 +175,17 @@ public DocumentCursor find(Filter filter) {
}
}
- public void createIndex(String field, IndexOptions indexOptions) {
+ public void createIndex(Fields fields, IndexOptions indexOptions) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
// by default async is false while creating index
try {
writeLock.lock();
if (indexOptions == null) {
- collectionOperations.createIndex(field, IndexType.Unique, false);
+ collectionOperations.createIndex(fields, IndexType.Unique, false);
} else {
- collectionOperations.createIndex(field, indexOptions.getIndexType(),
+ collectionOperations.createIndex(fields, indexOptions.getIndexType(),
indexOptions.isAsync());
}
} finally {
@@ -194,33 +193,33 @@ public void createIndex(String field, IndexOptions indexOptions) {
}
}
- public void rebuildIndex(String field, boolean isAsync) {
+ public void rebuildIndex(Fields fields, boolean isAsync) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
- IndexEntry indexEntry;
+ IndexDescriptor indexDescriptor;
try {
readLock.lock();
- indexEntry = collectionOperations.findIndex(field);
+ indexDescriptor = collectionOperations.findIndex(fields);
} finally {
readLock.unlock();
}
- if (indexEntry != null) {
- validateRebuildIndex(indexEntry);
+ if (indexDescriptor != null) {
+ validateRebuildIndex(indexDescriptor);
try {
writeLock.lock();
- collectionOperations.rebuildIndex(indexEntry, isAsync);
+ collectionOperations.rebuildIndex(indexDescriptor, isAsync);
} finally {
writeLock.unlock();
}
} else {
- throw new IndexingException(field + " is not indexed");
+ throw new IndexingException(fields + " is not indexed");
}
}
- public Collection listIndices() {
+ public Collection listIndices() {
checkOpened();
try {
@@ -231,37 +230,37 @@ public Collection listIndices() {
}
}
- public boolean hasIndex(String field) {
+ public boolean hasIndex(Fields fields) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
try {
readLock.lock();
- return collectionOperations.hasIndex(field);
+ return collectionOperations.hasIndex(fields);
} finally {
readLock.unlock();
}
}
- public boolean isIndexing(String field) {
+ public boolean isIndexing(Fields fields) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "field cannot be null");
try {
readLock.lock();
- return collectionOperations.isIndexing(field);
+ return collectionOperations.isIndexing(fields);
} finally {
readLock.unlock();
}
}
- public void dropIndex(String field) {
+ public void dropIndex(Fields fields) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
try {
writeLock.lock();
- collectionOperations.dropIndex(field);
+ collectionOperations.dropIndex(fields);
} finally {
writeLock.unlock();
}
@@ -407,11 +406,11 @@ private void checkOpened() {
}
}
- private void validateRebuildIndex(IndexEntry indexEntry) {
- notNull(indexEntry, "index cannot be null");
+ private void validateRebuildIndex(IndexDescriptor indexDescriptor) {
+ notNull(indexDescriptor, "index cannot be null");
- if (isIndexing(indexEntry.getField())) {
- throw new IndexingException("indexing on value " + indexEntry.getField() + " is currently running");
+ if (isIndexing(indexDescriptor.getFields())) {
+ throw new IndexingException("indexing on value " + indexDescriptor.getFields() + " is currently running");
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/DocumentCursor.java b/nitrite/src/main/java/org/dizitart/no2/collection/DocumentCursor.java
index ca4fcbf10..a3ef2e4c2 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/DocumentCursor.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/DocumentCursor.java
@@ -16,13 +16,13 @@
package org.dizitart.no2.collection;
-import org.dizitart.no2.common.Lookup;
-import org.dizitart.no2.common.NullOrder;
-import org.dizitart.no2.common.RecordStream;
-import org.dizitart.no2.common.SortOrder;
+import org.dizitart.no2.common.*;
+import org.dizitart.no2.common.tuples.Pair;
import java.text.Collator;
+import static org.dizitart.no2.common.Fields.multiple;
+
/**
* An interface to iterate over database {@code find()} results. It provides a
* mechanism to iterate over all {@link NitriteId}s of the result.
@@ -52,7 +52,7 @@
*/
public interface DocumentCursor extends RecordStream {
- DocumentCursor sort(String field, SortOrder sortOrder, Collator collator, NullOrder nullOrder);
+ DocumentCursor sort(Fields fields, Collator collator, NullOrder nullOrder);
DocumentCursor skipLimit(long skip, long size);
@@ -91,14 +91,18 @@ default DocumentCursor sort(String field) {
}
default DocumentCursor sort(String field, SortOrder sortOrder) {
- return sort(field, sortOrder, NullOrder.Default);
+ return sort(multiple(new Pair<>(field, sortOrder)), NullOrder.Default);
+ }
+
+ default DocumentCursor sort(Fields fields) {
+ return sort(fields, null, NullOrder.Default);
}
- default DocumentCursor sort(String field, SortOrder sortOrder, Collator collator) {
- return sort(field, sortOrder, collator, NullOrder.Default);
+ default DocumentCursor sort(Fields fields, Collator collator) {
+ return sort(fields, collator, NullOrder.Default);
}
- default DocumentCursor sort(String field, SortOrder sortOrder, NullOrder nullOrder) {
- return sort(field, sortOrder, null, nullOrder);
+ default DocumentCursor sort(Fields fields, NullOrder nullOrder) {
+ return sort(fields, null, nullOrder);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/NitriteCollection.java b/nitrite/src/main/java/org/dizitart/no2/collection/NitriteCollection.java
index 57da139de..fca4c3ee8 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/NitriteCollection.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/NitriteCollection.java
@@ -19,6 +19,7 @@
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.events.EventAware;
import org.dizitart.no2.collection.events.EventType;
+import org.dizitart.no2.collection.operation.FindOptions;
import org.dizitart.no2.common.PersistentCollection;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.common.event.EventBus;
@@ -42,17 +43,18 @@
* A nitrite collection supports indexing. Every nitrite collection is also
* observable.
*
- * [[app-listing]]
- * [source,java]
- * .Create a collection
- * --
- * // create/open a database
+ *
Create a collection
+ *
+ * {@code
* Nitrite db = Nitrite.builder()
- * .openOrCreate("user", "password");
- *
- * include::/src/docs/asciidoc/examples/collection.adoc[]
- *
- * --
+ * .loadModule(MVStoreModule("/tmp/tmp.db"))
+ * .openOrCreate("user", "password");
+ *
+ * NitriteCollection collection = db.getCollection("products");
+ * }
+ *
+ *
+ *
*
* @author Anindya Chatterjee
* @see EventAware
@@ -64,29 +66,29 @@
*/
public interface NitriteCollection extends PersistentCollection {
/**
- * Insert documents into a collection. If the document contains a '_id' value, then
+ * Insert documents into a collection. If the document contains a {@code _id} value, then
* the value will be used as a unique key to identify the document in the collection.
- * If the document does not contain any '_id' value, then nitrite will generate a new
+ * If the document does not contain any {@code _id} value, then nitrite will generate a new
* {@link NitriteId} and will add it to the document.
*
* If any of the value is already indexed in the collection, then after insertion the
* index will also be updated.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: These operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Insert}.
- *
+ *
+ *
* @param document the document to insert
* @param documents other documents to insert in a batch.
* @return the result of write operation.
- * @throws ValidationException if `document` is `null`.
- * @throws InvalidIdException if the '_id' value contains `null` value.
- * @throws InvalidIdException if the '_id' value contains non comparable type, i.e.
+ * @throws ValidationException if {@code document} is {@code null}.
+ * @throws InvalidIdException if the {@code _id} value contains {@code null} value.
+ * @throws InvalidIdException if the {@code _id} value contains non comparable type, i.e.
* type that does not implement {@link Comparable}.
- * @throws InvalidIdException if the '_id' contains value, which is not of the same java
- * type as of other documents' '_id' in the collection.
- * @throws UniqueConstraintException if the value of '_id' value clashes with the id
+ * @throws InvalidIdException if the {@code _id} contains value, which is not of the same java
+ * type as of other documents' {@code _id} in the collection.
+ * @throws UniqueConstraintException if the value of {@code _id} value clashes with the id
* of another document in the collection.
* @throws UniqueConstraintException if a value of the document is indexed and it
* violates the unique constraint in the collection(if any).
@@ -112,17 +114,17 @@ default WriteResult insert(Document document, Document... documents) {
/**
* Update documents in the collection.
*
- * If the `filter` is `null`, it will update all documents in the collection.
+ * If the {@code filter} is {@code null}, it will update all documents in the collection.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Update}.
+ *
*
* @param filter the filter to apply to select documents from the collection.
* @param update the modifications to apply.
* @return the result of the update operation.
- * @throws ValidationException if the `update` document is `null`.
+ * @throws ValidationException if the {@code update} document is {@code null}.
*/
default WriteResult update(Filter filter, Document update) {
return update(filter, update, new UpdateOptions());
@@ -130,22 +132,22 @@ default WriteResult update(Filter filter, Document update) {
/**
* Updates document in the collection. Update operation can be customized
- * with the help of `updateOptions`.
+ * with the help of {@code updateOptions}.
*
- * If the `filter` is `null`, it will update all documents in the collection unless
- * `justOnce` is set to `true` in `updateOptions`.
+ * If the {@code filter} is {@code null}, it will update all documents in the collection unless
+ * {@code justOnce} is set to {@code true} in {@code updateOptions}.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Update} or {@link EventType#Insert}.
+ *
*
* @param filter the filter to apply to select documents from the collection.
* @param update the modifications to apply.
* @param updateOptions the update options to customize the operation.
* @return the result of the update operation.
- * @throws ValidationException if the `update` document is `null`.
- * @throws ValidationException if `updateOptions` is `null`.
+ * @throws ValidationException if the {@code update} document is {@code null}.
+ * @throws ValidationException if {@code updateOptions} is {@code null}.
* @see UpdateOptions
*/
WriteResult update(Filter filter, Document update, UpdateOptions updateOptions);
@@ -153,12 +155,12 @@ default WriteResult update(Filter filter, Document update) {
/**
* Removes matching elements from the collection.
*
- * If the `filter` is `null`, it will remove all objects from the collection.
+ * If the {@code filter} is {@code null}, it will remove all objects from the collection.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Remove}.
+ *
*
* @param filter the filter to apply to select elements from collection.
* @return the result of the remove operation.
@@ -169,15 +171,15 @@ default WriteResult remove(Filter filter) {
/**
* Removes document from a collection. Remove operation can be customized by
- * `removeOptions`.
+ * {@code removeOptions}.
*
- * If the `filter` is `null`, it will remove all documents in the collection unless
- * `justOnce` is set to `true` in `removeOptions`.
+ * If the {@code filter} is {@code null}, it will remove all documents in the collection unless
+ * {@code justOnce} is set to {@code true} in {@code removeOptions}.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Remove}.
+ *
*
* @param filter the filter to apply to select documents from collection.
* @param justOne indicates if only one element will be removed or all of them.
@@ -190,7 +192,11 @@ default WriteResult remove(Filter filter) {
*
* @return a cursor to all documents in the collection.
*/
- DocumentCursor find();
+ default DocumentCursor find() {
+ return find(new FindOptions());
+ }
+
+ DocumentCursor find(FindOptions findOptions);
/**
* Applies a filter on the collection and returns a cursor to the
@@ -198,25 +204,29 @@ default WriteResult remove(Filter filter) {
*
* See {@link Filter} for all available filters.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: If there is an index on the value specified in the filter, this operation
* will take advantage of the index.
+ *
*
* @param filter the filter to apply to select documents from collection.
* @return a cursor to all selected documents.
- * @throws ValidationException if `filter` is null.
+ * @throws ValidationException if {@code filter} is null.
* @see Filter
* @see DocumentCursor#project(Document)
*/
- DocumentCursor find(Filter filter);
+ default DocumentCursor find(Filter filter) {
+ return find(filter, new FindOptions());
+ }
+
+ DocumentCursor find(Filter filter, FindOptions findOptions);
/**
* Gets a single element from the collection by its id. If no element
- * is found, it will return `null`.
+ * is found, it will return {@code null}.
*
* @param nitriteId the nitrite id
* @return the unique document associated with the nitrite id.
- * @throws ValidationException if `nitriteId` is `null`.
+ * @throws ValidationException if `nitriteId` is {@code null}.
*/
Document getById(NitriteId nitriteId);
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/BoundedDocumentStream.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/BoundedDocumentStream.java
index d7091542c..35bc2bc19 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/BoundedDocumentStream.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/BoundedDocumentStream.java
@@ -75,10 +75,10 @@ public BoundedIterator(final Iterator extends T> iterator, final long offset,
this.offset = offset;
this.size = size;
pos = 0;
- init();
+ initialize();
}
- private void init() {
+ private void initialize() {
while (pos < offset && iterator.hasNext()) {
iterator.next();
pos++;
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/CollectionOperations.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/CollectionOperations.java
index a083c318f..94db9e238 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/CollectionOperations.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/CollectionOperations.java
@@ -24,11 +24,12 @@
import org.dizitart.no2.collection.events.CollectionEventInfo;
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.meta.Attributes;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.common.event.EventBus;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.store.NitriteMap;
import java.util.Collection;
@@ -57,35 +58,35 @@ public CollectionOperations(String collectionName,
this.nitriteMap = nitriteMap;
this.nitriteConfig = nitriteConfig;
this.eventBus = eventBus;
- init();
+ initialize();
}
- public void createIndex(String field, String indexType, boolean async) {
- indexOperations.ensureIndex(field, indexType, async);
+ public void createIndex(Fields fields, String indexType, boolean async) {
+ indexOperations.createIndex(fields, indexType, async);
}
- public IndexEntry findIndex(String field) {
- return indexOperations.findIndexEntry(field);
+ public IndexDescriptor findIndex(Fields fields) {
+ return indexOperations.findIndexDescriptor(fields);
}
- public void rebuildIndex(IndexEntry indexEntry, boolean async) {
- indexOperations.rebuildIndex(indexEntry, async);
+ public void rebuildIndex(IndexDescriptor indexDescriptor, boolean async) {
+ indexOperations.buildIndex(indexDescriptor, async, true);
}
- public Collection listIndexes() {
+ public Collection listIndexes() {
return indexOperations.listIndexes();
}
- public boolean hasIndex(String field) {
- return indexOperations.hasIndexEntry(field);
+ public boolean hasIndex(Fields fields) {
+ return indexOperations.hasIndexEntry(fields);
}
- public boolean isIndexing(String field) {
- return indexOperations.isIndexing(field);
+ public boolean isIndexing(Fields fields) {
+ return indexOperations.isIndexing(fields);
}
- public void dropIndex(String field) {
- indexOperations.dropIndex(field);
+ public void dropIndex(Fields fields) {
+ indexOperations.dropIndex(fields);
}
public void dropAllIndices() {
@@ -143,15 +144,16 @@ public void close() {
}
}
- private void init() {
+ private void initialize() {
this.indexOperations = new IndexOperations(nitriteConfig, nitriteMap, eventBus);
- this.readOperations = new ReadOperations(collectionName, nitriteConfig, nitriteMap, indexOperations);
- this.writeOperations = new WriteOperations(indexOperations, readOperations,
- nitriteMap, eventBus);
+ DocumentIndexWriter indexWriter = new DocumentIndexWriter(nitriteConfig, nitriteMap, indexOperations);
+ this.readOperations = new ReadOperations(collectionName, nitriteConfig, nitriteMap, indexWriter);
+ this.writeOperations = new WriteOperations(indexWriter, readOperations, nitriteMap, eventBus);
}
private void dropNitriteMap() {
- NitriteMap catalogueMap = nitriteMap.getStore().openMap(COLLECTION_CATALOG, String.class, Document.class);
+ NitriteMap catalogueMap = nitriteMap.getStore().openMap(COLLECTION_CATALOG,
+ String.class, Document.class);
for (Pair entry : catalogueMap.entries()) {
String catalogue = entry.getFirst();
Document document = entry.getSecond();
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentCursorImpl.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentCursorImpl.java
index f6ca0a4de..71f96fad1 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentCursorImpl.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentCursorImpl.java
@@ -33,13 +33,19 @@
*/
class DocumentCursorImpl implements DocumentCursor {
private final RecordStream> recordStream;
+ private FindOptions findOptions;
DocumentCursorImpl(RecordStream> recordStream) {
this.recordStream = recordStream;
}
@Override
- public DocumentCursor sort(String field, SortOrder sortOrder, Collator collator, NullOrder nullOrder) {
+ public DocumentCursor sort(Fields fields, Collator collator, NullOrder nullOrder) {
+ findOptions = new FindOptions();
+ findOptions.collator(collator);
+ findOptions.nullOrder(nullOrder);
+ findOptions.sortBy(fields);
+
return new DocumentCursorImpl(new SortedDocumentCursor(field, sortOrder, collator,
nullOrder, recordStream));
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentIndexWriter.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentIndexWriter.java
new file mode 100644
index 000000000..434345d56
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/DocumentIndexWriter.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017-2020. Nitrite author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dizitart.no2.collection.operation;
+
+import org.dizitart.no2.NitriteConfig;
+import org.dizitart.no2.collection.Document;
+import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.Fields;
+import org.dizitart.no2.common.util.DocumentUtils;
+import org.dizitart.no2.index.IndexDescriptor;
+import org.dizitart.no2.index.NitriteIndexer;
+import org.dizitart.no2.store.IndexCatalog;
+import org.dizitart.no2.store.NitriteMap;
+import org.dizitart.no2.store.NitriteStore;
+
+import java.util.Collection;
+
+/**
+ * @author Anindya Chatterjee
+ */
+class DocumentIndexWriter {
+ private final NitriteConfig nitriteConfig;
+ private final NitriteMap nitriteMap;
+ private final IndexOperations indexOperations;
+ private String collectionName;
+ private IndexCatalog indexCatalog;
+
+ DocumentIndexWriter(NitriteConfig nitriteConfig,
+ NitriteMap nitriteMap,
+ IndexOperations indexOperations) {
+ this.nitriteConfig = nitriteConfig;
+ this.nitriteMap = nitriteMap;
+ this.indexOperations = indexOperations;
+ initialize();
+ }
+
+ void writeIndexEntry(Document document) {
+ Collection indexEntries = indexOperations.listIndexes();
+ if (indexEntries != null) {
+ for (IndexDescriptor indexDescriptor : indexEntries) {
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+
+ writeIndexEntryInternal(indexDescriptor, document, nitriteIndexer);
+ }
+ }
+ }
+
+ void removeIndexEntry(Document document) {
+ Collection indexEntries = indexOperations.listIndexes();
+ if (indexEntries != null) {
+ for (IndexDescriptor indexDescriptor : indexEntries) {
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+
+ removeIndexEntryInternal(indexDescriptor, document, nitriteIndexer);
+ }
+ }
+ }
+
+ void updateIndexEntry(Document oldDocument, Document newDocument) {
+ Collection indexEntries = indexOperations.listIndexes();
+ if (indexEntries != null) {
+ for (IndexDescriptor indexDescriptor : indexEntries) {
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+
+// Fields fields = indexDescriptor.getFields();
+// Object newValue = newDocument.get(field);
+// Object oldValue = oldDocument.get(field);
+//
+// if (newValue == null) continue;
+// if (newValue instanceof Comparable && oldValue instanceof Comparable) {
+// if (((Comparable) newValue).compareTo(oldValue) == 0) continue;
+// }
+//
+// validateDocumentIndexField(newValue, fields);
+//
+// if (indexCatalog.isDirtyIndex(collectionName, fields)
+// && !getBuildFlag(field).get()) {
+// // rebuild will also take care of the current document
+// rebuildIndex(indexDescriptor, true);
+// } else {
+// String indexType = indexDescriptor.getIndexType();
+// NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+// nitriteIndexer.updateIndex(nitriteMap, nitriteId, field, newValue, oldValue);
+// }
+
+ removeIndexEntryInternal(indexDescriptor, oldDocument, nitriteIndexer);
+ writeIndexEntryInternal(indexDescriptor, newDocument, nitriteIndexer);
+ }
+ }
+ }
+
+ private void initialize() {
+ NitriteStore> nitriteStore = nitriteConfig.getNitriteStore();
+ this.indexCatalog = nitriteStore.getIndexCatalog();
+ this.collectionName = nitriteMap.getName();
+ }
+
+ private void writeIndexEntryInternal(IndexDescriptor indexDescriptor, Document document,
+ NitriteIndexer nitriteIndexer) {
+ if (indexDescriptor != null) {
+ Fields fields = indexDescriptor.getFields();
+ FieldValues fieldValues = DocumentUtils.getValues(document, fields);
+
+// Object fieldValue = document.get(field);
+// validateDocumentIndexField(fieldValue, field);
+
+ // if dirty index and currently indexing is not running, rebuild
+ if (indexCatalog.isDirtyIndex(collectionName, fields)
+ && !indexOperations.getBuildFlag(fields).get()) {
+ // rebuild will also take care of the current document
+ indexOperations.buildIndex(indexDescriptor, true);
+ } else if (nitriteIndexer != null) {
+ nitriteIndexer.writeIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ }
+ }
+ }
+
+ private void removeIndexEntryInternal(IndexDescriptor indexDescriptor, Document document,
+ NitriteIndexer nitriteIndexer) {
+ if (indexDescriptor != null) {
+ Fields fields = indexDescriptor.getFields();
+ FieldValues fieldValues = DocumentUtils.getValues(document, fields);
+
+// Object fieldValue = document.get(field);
+// if (fieldValue == null) return;
+//
+// validateDocumentIndexField(fieldValue, field);
+
+ // if dirty index and currently indexing is not running, rebuild
+ if (indexCatalog.isDirtyIndex(collectionName, fields)
+ && !indexOperations.getBuildFlag(fields).get()) {
+ // rebuild will also take care of the current document
+ indexOperations.buildIndex(indexDescriptor, true);
+ } else if (nitriteIndexer != null) {
+ nitriteIndexer.removeIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ }
+ }
+ }
+
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/FindOptions.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/FindOptions.java
new file mode 100644
index 000000000..85da006a7
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/FindOptions.java
@@ -0,0 +1,21 @@
+package org.dizitart.no2.collection.operation;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.dizitart.no2.common.Fields;
+import org.dizitart.no2.common.NullOrder;
+
+import java.text.Collator;
+
+/**
+ * @author Anindya Chatterjee
+ */
+@Data
+@Accessors(fluent = true, chain = true)
+public class FindOptions {
+ private Fields sortBy;
+ private Collator collator;
+ private NullOrder nullOrder;
+ private long skip;
+ private long limit;
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/IndexOperations.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/IndexOperations.java
index aa51a8355..3f223eeaf 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/IndexOperations.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/IndexOperations.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (c) 2017-2020. Nitrite author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
package org.dizitart.no2.collection.operation;
import org.dizitart.no2.NitriteConfig;
@@ -22,23 +6,30 @@
import org.dizitart.no2.collection.events.CollectionEventInfo;
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.events.EventType;
-import org.dizitart.no2.common.tuples.Pair;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.concurrent.ThreadPoolManager;
import org.dizitart.no2.common.event.EventBus;
+import org.dizitart.no2.common.tuples.Pair;
+import org.dizitart.no2.common.util.DocumentUtils;
import org.dizitart.no2.exceptions.IndexingException;
-import org.dizitart.no2.index.IndexEntry;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.IndexDescriptor;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.store.IndexCatalog;
import org.dizitart.no2.store.NitriteMap;
import org.dizitart.no2.store.NitriteStore;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
-import static org.dizitart.no2.common.util.ValidationUtils.validateDocumentIndexField;
+import static org.dizitart.no2.common.concurrent.ThreadPoolManager.runAsync;
/**
* @author Anindya Chatterjee
@@ -47,17 +38,19 @@ class IndexOperations implements AutoCloseable {
private final NitriteConfig nitriteConfig;
private final NitriteMap nitriteMap;
private final EventBus, CollectionEventListener> eventBus;
+
private String collectionName;
private IndexCatalog indexCatalog;
- private Map indexBuildRegistry;
+ private Map indexBuildRegistry;
private ExecutorService rebuildExecutor;
+ private Collection indexDescriptorCache;
IndexOperations(NitriteConfig nitriteConfig, NitriteMap nitriteMap,
EventBus, CollectionEventListener> eventBus) {
this.nitriteConfig = nitriteConfig;
this.nitriteMap = nitriteMap;
this.eventBus = eventBus;
- init();
+ initialize();
}
@Override
@@ -67,230 +60,156 @@ public void close() {
}
}
- void ensureIndex(String field, String indexType, boolean isAsync) {
- IndexEntry indexEntry;
- if (!hasIndexEntry(field)) {
+ void createIndex(Fields fields, String indexType, boolean isAsync) {
+ IndexDescriptor indexDescriptor;
+ if (!hasIndexEntry(fields)) {
// if no index create index
- indexEntry = indexCatalog.createIndexEntry(collectionName, field, indexType);
+ indexDescriptor = indexCatalog.createIndexDescriptor(collectionName, fields, indexType);
} else {
// if index already there throw
- throw new IndexingException("index already exists on " + field);
- }
-
- rebuildIndex(indexEntry, isAsync);
- }
-
- void writeIndex(Document document, NitriteId nitriteId) {
- Collection indexEntries = listIndexes();
- if (indexEntries != null) {
- for (IndexEntry indexEntry : indexEntries) {
- String field = indexEntry.getField();
- String indexType = indexEntry.getIndexType();
- Indexer indexer = findIndexer(indexType);
-
- writeIndexEntry(field, document, nitriteId, indexer, indexEntry);
- }
+ throw new IndexingException("index already exists on " + fields);
}
- }
- void removeIndex(Document document, NitriteId nitriteId) {
- Collection indexEntries = listIndexes();
- if (indexEntries != null) {
- for (IndexEntry indexEntry : indexEntries) {
- String field = indexEntry.getField();
- String indexType = indexEntry.getIndexType();
- Indexer indexer = findIndexer(indexType);
+ buildIndex(indexDescriptor, isAsync, false);
- removeIndexEntry(field, document, nitriteId, indexer, indexEntry);
- }
- }
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- void updateIndex(Document oldDocument, Document newDocument, NitriteId nitriteId) {
- Collection indexEntries = listIndexes();
- if (indexEntries != null) {
- for (IndexEntry indexEntry : indexEntries) {
- String field = indexEntry.getField();
- Object newValue = newDocument.get(field);
- Object oldValue = oldDocument.get(field);
-
- if (newValue == null) continue;
- if (newValue instanceof Comparable && oldValue instanceof Comparable) {
- if (((Comparable) newValue).compareTo(oldValue) == 0) continue;
- }
-
- validateDocumentIndexField(newValue, field);
-
- if (indexCatalog.isDirtyIndex(collectionName, field)
- && !getBuildFlag(field).get()) {
- // rebuild will also take care of the current document
- rebuildIndex(indexEntry, true);
- } else {
- String indexType = indexEntry.getIndexType();
- Indexer indexer = findIndexer(indexType);
- indexer.updateIndex(nitriteMap, nitriteId, field, newValue, oldValue);
- }
- }
- }
+ // update descriptor cache
+ updateIndexDescriptorCache();
}
// call to this method is already synchronized, only one thread per field
// can access it only if rebuild is already not running for that field
- void rebuildIndex(IndexEntry indexEntry, boolean isAsync) {
- final String field = indexEntry.getField();
- if (getBuildFlag(field).compareAndSet(false, true)) {
+ void buildIndex(IndexDescriptor indexDescriptor, boolean isAsync, boolean rebuild) {
+ final Fields fields = indexDescriptor.getFields();
+ if (getBuildFlag(fields).compareAndSet(false, true)) {
if (isAsync) {
- rebuildExecutor.submit(() -> buildIndexInternal(field, indexEntry));
+ rebuildExecutor.submit(() -> buildIndexInternal(indexDescriptor, rebuild));
} else {
- buildIndexInternal(field, indexEntry);
+ buildIndexInternal(indexDescriptor, rebuild);
}
return;
}
- throw new IndexingException("indexing is already running on " + indexEntry.getField());
+ throw new IndexingException("indexing is already running on " + indexDescriptor.getFields());
}
- void dropIndex(String field) {
- if (getBuildFlag(field).get()) {
- throw new IndexingException("cannot drop index as indexing is running on " + field);
+ void dropIndex(Fields fields) {
+ if (getBuildFlag(fields).get()) {
+ throw new IndexingException("cannot drop index as indexing is running on " + fields);
}
- IndexEntry indexEntry = findIndexEntry(field);
- if (indexEntry != null) {
- String indexType = indexEntry.getIndexType();
- Indexer indexer = findIndexer(indexType);
- indexer.dropIndex(nitriteMap, field);
- indexCatalog.dropIndexEntry(collectionName, field);
- indexBuildRegistry.remove(field);
+ IndexDescriptor indexDescriptor = findIndexDescriptor(fields);
+ if (indexDescriptor != null) {
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+ nitriteIndexer.dropIndex(indexDescriptor, nitriteConfig);
+
+ indexCatalog.dropIndexDescriptor(collectionName, fields);
+ indexBuildRegistry.remove(fields);
+
+ // update descriptor cache
+ updateIndexDescriptorCache();
} else {
- throw new IndexingException(field + " is not indexed");
+ throw new IndexingException(fields + " is not indexed");
}
}
void dropAllIndices() {
- for (Map.Entry entry : indexBuildRegistry.entrySet()) {
+ for (Map.Entry entry : indexBuildRegistry.entrySet()) {
if (entry.getValue() != null && entry.getValue().get()) {
throw new IndexingException("cannot drop index as indexing is running on " + entry.getKey());
}
}
- for (IndexEntry index : listIndexes()) {
- dropIndex(index.getField());
+ List> futures = new ArrayList<>();
+ for (IndexDescriptor index : listIndexes()) {
+ futures.add(runAsync(() -> dropIndex(index.getFields())));
}
+
+ for (Future> future : futures) {
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new IndexingException("failed to drop all indices", e);
+ }
+ }
+
indexBuildRegistry.clear();
+
+ // update descriptor cache
+ updateIndexDescriptorCache();
}
- boolean isIndexing(String field) {
+ boolean isIndexing(Fields field) {
// has an index will only return true, if there is an index on
// the value and indexing is not running on it
- return indexCatalog.hasIndexEntry(collectionName, field)
+ return indexCatalog.hasIndexDescriptor(collectionName, field)
&& getBuildFlag(field).get();
}
- boolean hasIndexEntry(String field) {
- return indexCatalog.hasIndexEntry(collectionName, field);
+ boolean hasIndexEntry(Fields field) {
+ return indexCatalog.hasIndexDescriptor(collectionName, field);
}
- Collection listIndexes() {
- return indexCatalog.listIndexEntries(collectionName);
+ Collection listIndexes() {
+ return indexDescriptorCache;
}
- IndexEntry findIndexEntry(String field) {
- return indexCatalog.findIndexEntry(collectionName, field);
+ IndexDescriptor findIndexDescriptor(Fields field) {
+ return indexCatalog.findIndexDescriptor(collectionName, field);
}
- Indexer findIndexer(String indexType) {
- Indexer indexer = nitriteConfig.findIndexer(indexType);
- if (indexer != null) {
- return indexer;
- }
- throw new IndexingException("no indexer found for index type " + indexType);
+ AtomicBoolean getBuildFlag(Fields field) {
+ AtomicBoolean flag = indexBuildRegistry.get(field);
+ if (flag != null) return flag;
+
+ flag = new AtomicBoolean(false);
+ indexBuildRegistry.put(field, flag);
+ return flag;
}
- private void init() {
+ private void initialize() {
NitriteStore> nitriteStore = nitriteConfig.getNitriteStore();
this.indexCatalog = nitriteStore.getIndexCatalog();
this.collectionName = nitriteMap.getName();
this.indexBuildRegistry = new ConcurrentHashMap<>();
this.rebuildExecutor = ThreadPoolManager.workerPool();
+ updateIndexDescriptorCache();
+ }
+
+ private void updateIndexDescriptorCache() {
+ indexDescriptorCache = indexCatalog.listIndexDescriptors(collectionName);
}
- private void buildIndexInternal(final String field, final IndexEntry indexEntry) {
+ private void buildIndexInternal(IndexDescriptor indexDescriptor, boolean rebuild) {
+ Fields fields = indexDescriptor.getFields();
try {
- alert(EventType.IndexStart, field);
+ alert(EventType.IndexStart, fields);
// first put dirty marker
- indexCatalog.beginIndexing(collectionName, field);
+ indexCatalog.beginIndexing(collectionName, fields);
- String indexType = indexEntry.getIndexType();
- Indexer indexer = findIndexer(indexType);
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = nitriteConfig.findIndexer(indexType);
+
+ // if rebuild drop existing index
+ if (rebuild) {
+ nitriteIndexer.dropIndex(indexDescriptor, nitriteConfig);
+ }
- // re-create the index for the values of the field from document
for (Pair entry : nitriteMap.entries()) {
Document document = entry.getSecond();
- if (document.getFields().contains(field)) {
- // remove old values if exists
- removeIndexEntry(field, entry.getSecond(), entry.getFirst(), indexer, indexEntry);
-
- // re-create new entry
- writeIndexEntry(field, entry.getSecond(), entry.getFirst(), indexer, indexEntry);
- }
+ FieldValues fieldValues = DocumentUtils.getValues(document, indexDescriptor.getFields());
+ nitriteIndexer.writeIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
}
} finally {
// remove dirty marker to denote indexing completed successfully
// if dirty marker is found in any index, it needs to be rebuild
- indexCatalog.endIndexing(collectionName, field);
- getBuildFlag(field).set(false);
- alert(EventType.IndexEnd, field);
- }
- }
-
- private void writeIndexEntry(String field, Document document, NitriteId nitriteId,
- Indexer indexer, IndexEntry indexEntry) {
- if (indexEntry != null) {
- Object fieldValue = document.get(field);
- validateDocumentIndexField(fieldValue, field);
-
- // if dirty index and currently indexing is not running, rebuild
- if (indexCatalog.isDirtyIndex(collectionName, field)
- && !getBuildFlag(field).get()) {
- // rebuild will also take care of the current document
- rebuildIndex(indexEntry, true);
- } else if (indexer != null) {
- indexer.writeIndex(nitriteMap, nitriteId, field, fieldValue);
- }
+ indexCatalog.endIndexing(collectionName, fields);
+ getBuildFlag(fields).set(false);
+ alert(EventType.IndexEnd, fields);
}
}
- private void removeIndexEntry(String field, Document document, NitriteId nitriteId,
- Indexer indexer, IndexEntry indexEntry) {
- if (indexEntry != null) {
- Object fieldValue = document.get(field);
- if (fieldValue == null) return;
-
- validateDocumentIndexField(fieldValue, field);
-
- // if dirty index and currently indexing is not running, rebuild
- if (indexCatalog.isDirtyIndex(collectionName, field)
- && !getBuildFlag(field).get()) {
- // rebuild will also take care of the current document
- rebuildIndex(indexEntry, true);
- } else if (indexer != null) {
- indexer.removeIndex(nitriteMap, nitriteId, field, fieldValue);
- }
- }
- }
-
- private AtomicBoolean getBuildFlag(String field) {
- AtomicBoolean flag = indexBuildRegistry.get(field);
- if (flag != null) return flag;
-
- flag = new AtomicBoolean(false);
- indexBuildRegistry.put(field, flag);
- return flag;
- }
-
- private void alert(EventType eventType, String field) {
- CollectionEventInfo eventInfo = new CollectionEventInfo<>();
+ private void alert(EventType eventType, Fields field) {
+ CollectionEventInfo eventInfo = new CollectionEventInfo<>();
eventInfo.setItem(field);
eventInfo.setTimestamp(System.currentTimeMillis());
eventInfo.setEventType(eventType);
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 e7eebbf65..9fc37b8ec 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
@@ -23,8 +23,8 @@
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.common.RecordStream;
import org.dizitart.no2.filters.*;
-import org.dizitart.no2.index.IndexEntry;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.IndexDescriptor;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.store.NitriteMap;
import java.util.*;
@@ -38,31 +38,37 @@ class ReadOperations {
private final String collectionName;
private final NitriteConfig nitriteConfig;
private final NitriteMap nitriteMap;
- private final IndexOperations indexOperations;
+ private final DocumentIndexWriter documentIndexWriter;
ReadOperations(String collectionName,
NitriteConfig nitriteConfig,
NitriteMap nitriteMap,
- IndexOperations indexOperations) {
+ DocumentIndexWriter documentIndexWriter) {
this.nitriteMap = nitriteMap;
this.nitriteConfig = nitriteConfig;
this.collectionName = collectionName;
- this.indexOperations = indexOperations;
+ this.documentIndexWriter = documentIndexWriter;
}
- public DocumentCursor find() {
- RecordStream> recordStream = nitriteMap.entries();
+ public DocumentCursor find(FindOptions findOptions) {
+ RecordStream> recordStream = findSuitableStream(null, findOptions);
return new DocumentCursorImpl(recordStream);
}
- public DocumentCursor find(Filter filter) {
+ public DocumentCursor find(Filter filter, FindOptions findOptions) {
if (filter == null || filter == Filter.ALL) {
- return find();
+ return find(findOptions);
}
+ // get all indices for this collection
+ // find the suitable index (prefix included)
+ // find the index map
+ // supply indexmap, collectionmap to filter
+
+
prepareFilter(filter);
- RecordStream> recordStream = findSuitableStream(filter);
+ RecordStream> recordStream = findSuitableStream(filter, findOptions);
return new DocumentCursorImpl(recordStream);
}
@@ -106,12 +112,12 @@ private void prepareLogicalFilter(LogicalFilter logicalFilter) {
private void prepareIndexedFilter(IndexAwareFilter indexAwareFilter) {
String field = indexAwareFilter.getField();
- IndexEntry indexEntry = indexOperations.findIndexEntry(field);
- if (indexEntry != null) {
- String indexType = indexEntry.getIndexType();
- Indexer indexer = indexOperations.findIndexer(indexType);
- if (indexer != null) {
- indexAwareFilter.setIndexer(indexer);
+ IndexDescriptor indexDescriptor = documentIndexWriter.findIndexDescriptor(field);
+ if (indexDescriptor != null) {
+ String indexType = indexDescriptor.getIndexType();
+ NitriteIndexer nitriteIndexer = documentIndexWriter.findIndexer(indexType);
+ if (nitriteIndexer != null) {
+ indexAwareFilter.setNitriteIndexer(nitriteIndexer);
indexAwareFilter.setIsFieldIndexed(true);
}
} else {
@@ -122,12 +128,14 @@ private void prepareIndexedFilter(IndexAwareFilter indexAwareFilter) {
}
}
- private RecordStream> findSuitableStream(Filter filter) {
+ private RecordStream> findSuitableStream(Filter filter, FindOptions findOptions) {
if (filter instanceof AndFilter) {
AndFilter andFilter = (AndFilter) filter;
Filter lhs = andFilter.getLhs();
Filter rhs = andFilter.getRhs();
+ // TODO: check if compound index is supported
+
if (lhs instanceof IndexAwareFilter && ((IndexAwareFilter) lhs).getIsFieldIndexed()) {
// Indexed AND Filter => IndexScan (LHS) -> Filter (RHS)
@@ -195,6 +203,8 @@ private RecordStream> getUnionStream(
}
private RecordStream> getIndexedStream(IndexAwareFilter indexAwareFilter) {
+ // TODO: check if prefix of compound index is possible
+
return new IndexedStream(indexAwareFilter, nitriteMap);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/SortedDocumentCursor.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/SortedDocumentCursor.java
index 3f3acf7f9..04bec304d 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/SortedDocumentCursor.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/SortedDocumentCursor.java
@@ -74,7 +74,7 @@ public SortedDocumentIterator(String field,
this.collator = collator;
this.nullOrder = nullOrder;
this.iterator = iterator;
- init();
+ initialize();
}
@Override
@@ -87,7 +87,7 @@ public Pair next() {
return sortedIterator.next();
}
- private void init() {
+ private void initialize() {
NavigableMap>> sortedMap;
if (collator != null) {
sortedMap = new TreeMap<>(collator);
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/StreamGenerator.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/StreamGenerator.java
new file mode 100644
index 000000000..26e3f4127
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/StreamGenerator.java
@@ -0,0 +1,11 @@
+package org.dizitart.no2.collection.operation;
+
+import org.dizitart.no2.common.RecordStream;
+
+/**
+ *
+ * @author Anindya Chatterjee
+ */
+public interface StreamGenerator {
+ RecordStream generate(FindOptions options);
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/collection/operation/WriteOperations.java b/nitrite/src/main/java/org/dizitart/no2/collection/operation/WriteOperations.java
index b03b3dd01..866fa689b 100644
--- a/nitrite/src/main/java/org/dizitart/no2/collection/operation/WriteOperations.java
+++ b/nitrite/src/main/java/org/dizitart/no2/collection/operation/WriteOperations.java
@@ -26,6 +26,7 @@
import org.dizitart.no2.collection.events.EventType;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.common.event.EventBus;
+import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.filters.Filter;
import org.dizitart.no2.store.NitriteMap;
@@ -40,16 +41,16 @@
*/
@Slf4j
class WriteOperations {
- private final IndexOperations indexOperations;
+ private final DocumentIndexWriter documentIndexWriter;
private final ReadOperations readOperations;
private final EventBus, CollectionEventListener> eventBus;
private final NitriteMap nitriteMap;
- WriteOperations(IndexOperations indexOperations,
+ WriteOperations(DocumentIndexWriter documentIndexWriter,
ReadOperations readOperations,
NitriteMap nitriteMap,
EventBus, CollectionEventListener> eventBus) {
- this.indexOperations = indexOperations;
+ this.documentIndexWriter = documentIndexWriter;
this.readOperations = readOperations;
this.eventBus = eventBus;
this.nitriteMap = nitriteMap;
@@ -60,25 +61,25 @@ WriteResult insert(Document... documents) {
log.debug("Total {} document(s) to be inserted in {}", documents.length, nitriteMap.getName());
for (Document document : documents) {
- Document item = document.clone();
- NitriteId nitriteId = item.getId();
- String source = item.getSource();
+ Document newDoc = document.clone();
+ NitriteId nitriteId = newDoc.getId();
+ String source = newDoc.getSource();
long time = System.currentTimeMillis();
- if (!REPLICATOR.contentEquals(item.getSource())) {
+ if (!REPLICATOR.contentEquals(newDoc.getSource())) {
// if replicator is not inserting the document that means
// it is being inserted by user, so update metadata
- item.remove(DOC_SOURCE);
- item.put(DOC_REVISION, 1);
- item.put(DOC_MODIFIED, time);
+ newDoc.remove(DOC_SOURCE);
+ newDoc.put(DOC_REVISION, 1);
+ newDoc.put(DOC_MODIFIED, time);
} else {
// if replicator is inserting the document, remove the source
// but keep the revision intact
- item.remove(DOC_SOURCE);
+ newDoc.remove(DOC_SOURCE);
}
- log.debug("Inserting document {} in {}", item, nitriteMap.getName());
- Document already = nitriteMap.putIfAbsent(nitriteId, item);
+ log.debug("Inserting document {} in {}", newDoc, nitriteMap.getName());
+ Document already = nitriteMap.putIfAbsent(nitriteId, newDoc);
if (already != null) {
log.warn("Another document {} already exists with same id {}", already, nitriteId);
@@ -87,18 +88,18 @@ WriteResult insert(Document... documents) {
"entry with same id already exists in " + nitriteMap.getName());
} else {
try {
- indexOperations.writeIndex(item, nitriteId);
- } catch (UniqueConstraintException uce) {
- log.error("Unique constraint violated for the document "
- + document + " in " + nitriteMap.getName(), uce);
+ documentIndexWriter.writeIndexEntry(newDoc);
+ } catch (UniqueConstraintException | IndexingException e) {
+ log.error("Index operation has failed during insertion for the document "
+ + document + " in " + nitriteMap.getName(), e);
nitriteMap.remove(nitriteId);
- throw uce;
+ throw e;
}
}
nitriteIds.add(nitriteId);
- Document eventDoc = item.clone();
+ Document eventDoc = newDoc.clone();
CollectionEventInfo eventInfo = new CollectionEventInfo<>();
eventInfo.setItem(eventDoc);
eventInfo.setTimestamp(time);
@@ -171,7 +172,15 @@ WriteResult update(Filter filter, Document update, UpdateOptions updateOptions)
writeResult.addToList(nitriteId);
}
- indexOperations.updateIndex(oldDocument, item, nitriteId);
+ try {
+ documentIndexWriter.updateIndexEntry(oldDocument, item);
+ } catch (UniqueConstraintException | IndexingException e) {
+ log.error("Index operation failed during update, reverting changes for the document "
+ + oldDocument + " in " + nitriteMap.getName(), e);
+ nitriteMap.put(nitriteId, oldDocument);
+ documentIndexWriter.updateIndexEntry(item, oldDocument);
+ throw e;
+ }
CollectionEventInfo eventInfo = new CollectionEventInfo<>();
Document eventDoc = item.clone();
@@ -238,7 +247,7 @@ WriteResult remove(Filter filter, boolean justOnce) {
return result;
}
- public WriteResult remove(Document document) {
+ WriteResult remove(Document document) {
WriteResultImpl result = new WriteResultImpl();
CollectionEventInfo eventInfo = removeAndCreateEvent(document, result);
if (eventInfo != null) {
@@ -253,7 +262,7 @@ private CollectionEventInfo removeAndCreateEvent(Document document, Wr
document = nitriteMap.remove(nitriteId);
if (document != null) {
long time = System.currentTimeMillis();
- indexOperations.removeIndex(document, nitriteId);
+ documentIndexWriter.removeIndexEntry(document);
writeResult.addToList(nitriteId);
int rev = document.getRevision();
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/NullEntry.java b/nitrite/src/main/java/org/dizitart/no2/common/DBNull.java
similarity index 54%
rename from nitrite/src/main/java/org/dizitart/no2/common/NullEntry.java
rename to nitrite/src/main/java/org/dizitart/no2/common/DBNull.java
index ac56c9079..1e2d95b7a 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/NullEntry.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/DBNull.java
@@ -7,19 +7,19 @@
*
* @author Anindya Chatterjee
*/
-public class NullEntry implements Comparable, Serializable {
+public class DBNull implements Comparable, Serializable {
private static final long serialVersionUID = 1598819770L;
- private static final NullEntry instance = new NullEntry();
+ private static final DBNull instance = new DBNull();
- private NullEntry() {
+ private DBNull() {
}
@Override
- public int compareTo(NullEntry o) {
+ public int compareTo(DBNull o) {
return 0;
}
- public static NullEntry getInstance() {
+ public static DBNull getInstance() {
return instance;
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/FieldValues.java b/nitrite/src/main/java/org/dizitart/no2/common/FieldValues.java
new file mode 100644
index 000000000..0c6598041
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/common/FieldValues.java
@@ -0,0 +1,46 @@
+package org.dizitart.no2.common;
+
+import lombok.Data;
+import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.common.tuples.Pair;
+import org.dizitart.no2.exceptions.ValidationException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Anindya Chatterjee
+ */
+@Data
+public class FieldValues {
+ private NitriteId nitriteId;
+ private Fields fields;
+ private List> values;
+
+ public FieldValues() {
+ values = new ArrayList<>();
+ }
+
+ public Object get(String field) {
+ if (fields.getFieldNames().contains(field)) {
+ for (Pair value : values) {
+ if (value.getFirst().equals(field)) {
+ return value.getSecond();
+ }
+ }
+ }
+ return null;
+ }
+
+ public Object getFirstValue() {
+ return getValueAt(0);
+ }
+
+ public Object getValueAt(int index) {
+ if (index > values.size() - 1) {
+ throw new ValidationException("invalid index provided");
+ }
+
+ return values.get(index).getSecond();
+ }
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/Fields.java b/nitrite/src/main/java/org/dizitart/no2/common/Fields.java
new file mode 100644
index 000000000..f472ef254
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/common/Fields.java
@@ -0,0 +1,127 @@
+package org.dizitart.no2.common;
+
+import lombok.Data;
+import org.dizitart.no2.common.tuples.Pair;
+import org.dizitart.no2.common.util.StringUtils;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.dizitart.no2.common.Constants.INTERNAL_NAME_SEPARATOR;
+import static org.dizitart.no2.common.util.ValidationUtils.notEmpty;
+import static org.dizitart.no2.common.util.ValidationUtils.notNull;
+
+/**
+ * @author Anindya Chatterjee
+ */
+@Data
+public class Fields implements Comparable, Serializable {
+ private static final long serialVersionUID = 1601646404L;
+
+ // order of the given fields matter
+ private List> fieldList;
+ private transient List fieldNames;
+
+ private Fields() {
+ fieldList = new ArrayList<>();
+ }
+
+ public static Fields single(String field) {
+ Fields fields = new Fields();
+ fields.fieldList.add(new Pair<>(field, SortOrder.Ascending));
+ return fields;
+ }
+
+ @SafeVarargs
+ public static Fields multiple(Pair... fields) {
+ notNull(fields, "fields cannot be null");
+ notEmpty(fields, "fields cannot be empty");
+
+ Fields f = new Fields();
+ f.fieldList.addAll(Arrays.asList(fields));
+ return f;
+ }
+
+ public List getFieldNames() {
+ if (fieldNames != null) {
+ return fieldNames;
+ }
+
+ fieldNames = new ArrayList<>();
+ for (Pair pair : fieldList) {
+ fieldNames.add(pair.getFirst());
+ }
+ return fieldNames;
+ }
+
+ public Pair getFirstKey() {
+ return fieldList.get(0);
+ }
+
+ public SortOrder getSortOrder(String fieldName) {
+ for (Pair pair : fieldList) {
+ if (pair.getFirst().equals(fieldName)) {
+ return pair.getSecond();
+ }
+ }
+ return null;
+ }
+
+ public String getEncodedName() {
+ return StringUtils.join(INTERNAL_NAME_SEPARATOR, getFieldNames());
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder("[");
+ int count = 0;
+ for (Pair field : fieldList) {
+ count++;
+ stringBuilder.append("{")
+ .append(field.getFirst())
+ .append(": ")
+ .append(field.getSecond())
+ .append("}");
+
+ if (count != fieldList.size()) {
+ stringBuilder.append(", ");
+ }
+ }
+ stringBuilder.append("]");
+ return stringBuilder.toString();
+ }
+
+ @Override
+ public int compareTo(Fields other) {
+ if (other == null) return 1;
+ int fieldsSize = getFieldNames().size();
+ int otherFieldsSize = other.getFieldNames().size();
+ int result = Integer.compare(fieldsSize, otherFieldsSize);
+ if (result == 0) {
+ String[] keys = getFieldNames().toArray(new String[0]);
+ String[] otherKeys = other.getFieldNames().toArray(new String[0]);
+ for (int i = 0; i < keys.length; i++) {
+ int cmp = keys[i].compareTo(otherKeys[i]);
+ if (cmp != 0) {
+ return cmp;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.writeObject(fieldList);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ fieldList = (List>) stream.readObject();
+ }
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/PersistentCollection.java b/nitrite/src/main/java/org/dizitart/no2/common/PersistentCollection.java
index 205d4d52b..f0413719e 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/PersistentCollection.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/PersistentCollection.java
@@ -22,7 +22,7 @@
import org.dizitart.no2.collection.events.EventAware;
import org.dizitart.no2.collection.events.EventType;
import org.dizitart.no2.collection.meta.MetadataAware;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.repository.ObjectRepository;
@@ -31,6 +31,9 @@
import java.io.Closeable;
import java.util.Collection;
+import static org.dizitart.no2.common.Fields.multiple;
+import static org.dizitart.no2.common.Fields.single;
+
/**
* The interface Persistent collection.
*
@@ -42,73 +45,146 @@
*/
public interface PersistentCollection extends EventAware, MetadataAware, Closeable {
/**
- * Creates an index on `value`, if not already exists.
- * If `indexOptions` is `null`, it will use default options.
+ * Creates an index on the {@code field}, if not already exists.
+ * If {@code indexOptions} is {@code null}, it will use default options.
*
- * The default indexing option is -
*
- * - `indexOptions.setAsync(false);`
- * - `indexOptions.setIndexType(IndexType.Unique);`
+ * The default indexing option is -
+ *
+ *
+ * {@code indexOptions.setAsync(false);}
+ * {@code indexOptions.setIndexType(IndexType.Unique);}
+ *
+ *
*
- * [icon="{@docRoot}/note.png"]
- * [NOTE]
- * ====
- * - '_id' value of the document is always indexed. But full text
- * indexing is not supported on '_id' value.
- * - Compound index is not supported.
- * - Indexing on arrays or collection is not supported
- * - Indexing on non-comparable value is not supported
- * ====
- *
- * @param field the value to be indexed.
+ * NOTE:
+ *
+ * _id value of the document is always indexed. But full-text indexing is not supported on _id value.
+ * Indexing on non-comparable value is not supported.
+ *
+ *
+ *
+ * @param field the field to be indexed.
* @param indexOptions index options.
- * @throws org.dizitart.no2.exceptions.IndexingException if an index already exists on `value`.
+ * @throws org.dizitart.no2.exceptions.IndexingException if an index already exists on the field.
* @see org.dizitart.no2.index.IndexOptions
* @see IndexType
*/
- void createIndex(String field, IndexOptions indexOptions);
+ default void createIndex(String field, IndexOptions indexOptions) {
+ createIndex(single(field), indexOptions);
+ }
/**
- * Rebuilds index on `field` if it exists.
+ * Creates an index on {@code fields}, if not already exists.
+ * If {@code indexOptions} is {@code null}, it will use default options.
+ *
+ *
+ * The default indexing option is -
*
- * @param field the value to be indexed.
- * @param isAsync if set to `true`, the indexing will run in background; otherwise, in foreground.
- * @throws org.dizitart.no2.exceptions.IndexingException if the `field` is not indexed.
+ *
+ * {@code indexOptions.setAsync(false);}
+ * {@code indexOptions.setIndexType(IndexType.Unique);}
+ *
+ *
+ *
+ * NOTE:
+ *
+ * _id value of the document is always indexed. But full-text indexing is not supported on _id value.
+ * Indexing on non-comparable value is not supported.
+ *
+ *
+ *
+ * @param fields the fields
+ * @param indexOptions the index options
+ * @throws org.dizitart.no2.exceptions.IndexingException if an index already exists on the fields.
+ * @see org.dizitart.no2.index.IndexOptions
+ * @see IndexType
*/
- void rebuildIndex(String field, boolean isAsync);
+ void createIndex(Fields fields, IndexOptions indexOptions);
+
+ /**
+ * Rebuilds index on the {@code field} if it exists.
+ *
+ * @param field the field to be indexed.
+ * @param isAsync if set to {@code true}, the indexing will run in background; otherwise, in foreground.
+ * @throws org.dizitart.no2.exceptions.IndexingException if the {@code field} is not indexed.
+ */
+ default void rebuildIndex(String field, boolean isAsync) {
+ rebuildIndex(single(field), isAsync);
+ }
+
+ /**
+ * Rebuilds index on {@code fields} if it exists.
+ *
+ * @param fields the fields to be indexed.
+ * @param isAsync if set to {@code true}, the indexing will run in background; otherwise, in foreground.
+ * @throws org.dizitart.no2.exceptions.IndexingException if the {@code fields} is not indexed.
+ */
+ void rebuildIndex(Fields fields, boolean isAsync);
/**
* Gets a set of all indices in the collection.
*
* @return a set of all indices.
- * @see IndexEntry
+ * @see IndexDescriptor
*/
- Collection listIndices();
+ Collection listIndices();
/**
- * Checks if a value is already indexed or not.
+ * Checks if the {@code field} is already indexed or not.
*
- * @param field the value to check.
- * @return `true` if the `value` is indexed; otherwise, `false`.
+ * @param field the field to check.
+ * @return {@code true} if the {@code field} is indexed; otherwise, {@code false}.
*/
- boolean hasIndex(String field);
+ default boolean hasIndex(String field) {
+ return hasIndex(single(field));
+ }
/**
- * Checks if indexing operation is currently ongoing for a `field`.
+ * Checks if the fields are already indexed or not.
*
- * @param field the value to check.
- * @return `true` if indexing is currently running; otherwise, `false`.
+ * @param fields the fields to check
+ * @return {@code true} if the {@code fields} are indexed; otherwise, {@code false}.
*/
- boolean isIndexing(String field);
+ boolean hasIndex(Fields fields);
/**
- * Drops the index on a `field`.
+ * Checks if indexing operation is currently ongoing for the {@code field}.
*
- * @param field the index of the `field` to drop.
- * @throws org.dizitart.no2.exceptions.IndexingException if indexing is currently running on the `field`.
- * @throws org.dizitart.no2.exceptions.IndexingException if the `field` is not indexed.
+ * @param field the field to check.
+ * @return {@code true} if indexing is currently running; otherwise, {@code false}.
*/
- void dropIndex(String field);
+ default boolean isIndexing(String field) {
+ return isIndexing(single(field));
+ }
+
+ /**
+ * Checks if indexing operation is currently ongoing for the {@code fields}.
+ *
+ * @param fields the fields to check.
+ * @return {@code true} if indexing is currently running; otherwise, {@code false}.
+ */
+ boolean isIndexing(Fields fields);
+
+ /**
+ * Drops the index on the {@code field}.
+ *
+ * @param field the index of the {@code field} to drop.
+ * @throws org.dizitart.no2.exceptions.IndexingException if indexing is currently running on the {@code field}.
+ * @throws org.dizitart.no2.exceptions.IndexingException if the {@code field} is not indexed.
+ */
+ default void dropIndex(String field) {
+ dropIndex(multiple(field));
+ }
+
+ /**
+ * Drops the index on the {@code fields}.
+ *
+ * @param fields the index of the {@code fields} to drop.
+ * @throws org.dizitart.no2.exceptions.IndexingException if indexing is currently running on the {@code fields}.
+ * @throws org.dizitart.no2.exceptions.IndexingException if the {@code fields} is not indexed.
+ */
+ void dropIndex(Fields fields);
/**
* Drops all indices from the collection.
@@ -118,27 +194,27 @@ public interface PersistentCollection extends EventAware, MetadataAware, Clos
void dropAllIndices();
/**
- * Inserts elements into this collection. If the element has an '_id' field,
+ * Inserts elements into this collection. If the element has an _id field,
* then the value will be used as an unique key to identify the element
- * in the collection. If the element does not have any '_id' field,
- * then nitrite will generate a new {@link org.dizitart.no2.collection.NitriteId} and will add it to the '_id'
+ * in the collection. If the element does not have any _id field,
+ * then nitrite will generate a new {@link org.dizitart.no2.collection.NitriteId} and will add it to the _id
* field.
*
* If any of the value is already indexed in the collection, then after insertion the
* index will also be updated.
*
- * [icon="{@docRoot}/note.png"]
- * NOTE: This operations will notify all {@link CollectionEventListener}
- * instances registered to this collection with change type
- * {@link EventType#Insert}.
+ *
+ * NOTE: This operations will notify all {@link CollectionEventListener}
+ * instances registered to this collection with change type {@link EventType#Insert}.
+ *
*
* @param elements an array of element for batch insertion.
* @return the result of the write operation.
- * @throws org.dizitart.no2.exceptions.ValidationException if `elements` is `null`.
- * @throws org.dizitart.no2.exceptions.InvalidIdException if the '_id' field's value contains `null`.
- * @throws org.dizitart.no2.exceptions.InvalidIdException if the '_id' field's value contains non comparable type, i.e. type that does not implement {@link Comparable}.
- * @throws org.dizitart.no2.exceptions.InvalidIdException if the '_id' field contains value which is not of the same java type as of other element's '_id' field value in the collection.
- * @throws org.dizitart.no2.exceptions.UniqueConstraintException if the value of '_id' field clashes with the '_id' field of another element in the repository.
+ * @throws org.dizitart.no2.exceptions.ValidationException if elements is null.
+ * @throws org.dizitart.no2.exceptions.InvalidIdException if the _id field's value contains {@code null}.
+ * @throws org.dizitart.no2.exceptions.InvalidIdException if the _id field's value contains non comparable type, i.e. type that does not implement {@link Comparable}.
+ * @throws org.dizitart.no2.exceptions.InvalidIdException if the _id field contains value which is not of the same java type as of other element's _id field value in the collection.
+ * @throws org.dizitart.no2.exceptions.UniqueConstraintException if the value of _id field clashes with the _id field of another element in the repository.
* @throws org.dizitart.no2.exceptions.UniqueConstraintException if a value of the element is indexed and it violates the unique constraint in the collection(if any).
* @see NitriteId
* @see WriteResult
@@ -146,61 +222,59 @@ public interface PersistentCollection extends EventAware, MetadataAware, Clos
WriteResult insert(T[] elements);
/**
- * Updates `element` in the collection. Specified `element` must have an id.
+ * Updates the {@code element} in the collection. Specified {@code element} must have an id.
*
- * [icon="{@docRoot}/note.png"]
- * NOTE: This operations will notify all {@link CollectionEventListener}
- * instances registered to this collection with change type
- * {@link EventType#Update}.
+ * NOTE: This operations will notify all {@link CollectionEventListener}
+ * instances registered to this collection with change type
+ * {@link EventType#Update}.
+ *
*
* @param element the element to update.
* @return the result of the update operation.
- * @throws org.dizitart.no2.exceptions.ValidationException if the `element` is `null`.
- * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the `element` does not have any id.
+ * @throws org.dizitart.no2.exceptions.ValidationException if the element is {@code null}.
+ * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the element does not have any id.
*/
default WriteResult update(T element) {
return update(element, false);
}
/**
- * Updates `element` in the collection. Specified `element` must have an id.
- * If the `element` is not found in the collection, it will be inserted only if `upsert`
- * is set to `true`.
+ * Updates {@code element} in the collection. Specified {@code element} must have an id.
+ * If the {@code element} is not found in the collection, it will be inserted only if {@code insertIfAbsent}
+ * is set to {@code true}.
*
- * [icon="{@docRoot}/note.png"]
+ *
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
- * {@link EventType#Update}
- * or {@link EventType#Insert}.
+ * {@link EventType#Update} or {@link EventType#Insert}.
+ *
*
* @param element the element to update.
- * @param insertIfAbsent if set to `true`, `element` will be inserted if not found.
+ * @param insertIfAbsent if set to {@code true}, {@code element} will be inserted if not found.
* @return the result of the update operation.
- * @throws org.dizitart.no2.exceptions.ValidationException if the `element` is `null`.
- * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the `element`
- * does not have any id field.
+ * @throws org.dizitart.no2.exceptions.ValidationException if the {@code element} is {@code null}.
+ * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the {@code element} does not have any id field.
*/
WriteResult update(T element, boolean insertIfAbsent);
/**
- * Deletes the `element` from the collection. The `element` must have an id.
+ * Deletes the {@code element} from the collection. The {@code element} must have an id.
+ *
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Remove}.
+ *
*
* @param element the element
* @return the result of the remove operation.
- * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the `element` does not
- * have any id field.
+ * @throws org.dizitart.no2.exceptions.NotIdentifiableException if the {@code element} does not have any id field.
*/
WriteResult remove(T element);
/**
* Removes all element from the collection.
- *
- * */
+ */
void clear();
/**
@@ -213,14 +287,14 @@ default WriteResult update(T element) {
void drop();
/**
- * Returns `true` if the collection is dropped; otherwise, `false`.
+ * Returns {@code true} if the collection is dropped; otherwise, {@code false}.
*
* @return a boolean value indicating if the collection has been dropped or not.
*/
boolean isDropped();
/**
- * Returns `true` if the collection is open; otherwise, `false`.
+ * Returns {@code true} if the collection is open; otherwise, {@code false}.
*
* @return a boolean value indicating if the collection has been closed or not.
*/
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/concurrent/ThreadPoolManager.java b/nitrite/src/main/java/org/dizitart/no2/common/concurrent/ThreadPoolManager.java
index a3921546b..7afa2db25 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/concurrent/ThreadPoolManager.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/concurrent/ThreadPoolManager.java
@@ -22,6 +22,7 @@
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.dizitart.no2.common.Constants.DAEMON_THREAD_NAME;
@@ -81,8 +82,8 @@ public Thread createThread(Runnable runnable) {
};
}
- public static void runAsync(Runnable runnable) {
- commonPool.submit(runnable);
+ public static Future> runAsync(Runnable runnable) {
+ return commonPool.submit(runnable);
}
public static void shutdownThreadPools() {
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/util/DocumentUtils.java b/nitrite/src/main/java/org/dizitart/no2/common/util/DocumentUtils.java
index 17648771f..ad2cd8f62 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/util/DocumentUtils.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/util/DocumentUtils.java
@@ -17,10 +17,13 @@
package org.dizitart.no2.common.util;
import org.dizitart.no2.collection.Document;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.filters.Filter;
import org.dizitart.no2.mapper.NitriteMapper;
+import java.util.ArrayList;
import java.util.Objects;
import static org.dizitart.no2.common.util.ObjectUtils.newInstance;
@@ -87,6 +90,20 @@ public static boolean isSimilar(Document document, Document other, String... fie
return result;
}
+ public static FieldValues getValues(Document document, Fields fields) {
+ FieldValues fieldValues = new FieldValues();
+ fieldValues.setNitriteId(document.getId());
+ fieldValues.setFields(fields);
+ fieldValues.setValues(new ArrayList<>());
+
+ for (String field : fields.getFieldNames()) {
+ Object value = document.get(field);
+ fieldValues.getValues().add(new Pair<>(field, value));
+ }
+
+ return fieldValues;
+ }
+
private static Document removeValues(Document document) {
if (document == null) return null;
for (Pair entry : document) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/util/Iterables.java b/nitrite/src/main/java/org/dizitart/no2/common/util/Iterables.java
index f106d68f7..d8879b272 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/util/Iterables.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/util/Iterables.java
@@ -16,6 +16,8 @@
package org.dizitart.no2.common.util;
+import org.dizitart.no2.common.UnknownType;
+
import java.lang.reflect.Array;
import java.util.*;
@@ -115,6 +117,14 @@ public static List listOf(T... items) {
return Collections.emptyList();
}
+ @SafeVarargs
+ public static Set setOf(T... items) {
+ if (items != null) {
+ return new HashSet<>(Arrays.asList(items));
+ }
+ return Collections.emptySet();
+ }
+
public static long size(Iterable> iterable) {
if (iterable instanceof Collection) {
return ((Collection>) iterable).size();
@@ -127,6 +137,15 @@ public static long size(Iterable> iterable) {
return count;
}
+ public static Class> getElementType(Iterable> iterable) {
+ if (iterable == null) return UnknownType.class;
+ Iterator> iterator = iterable.iterator();
+ if (iterator.hasNext()) {
+ return iterator.next().getClass();
+ }
+ return UnknownType.class;
+ }
+
@SuppressWarnings({"unchecked", "rawtypes"})
static Object[] toArray(Iterable iterable) {
if (iterable instanceof Collection) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/common/util/StringUtils.java b/nitrite/src/main/java/org/dizitart/no2/common/util/StringUtils.java
index 607a8786e..0659cdf00 100644
--- a/nitrite/src/main/java/org/dizitart/no2/common/util/StringUtils.java
+++ b/nitrite/src/main/java/org/dizitart/no2/common/util/StringUtils.java
@@ -16,6 +16,7 @@
package org.dizitart.no2.common.util;
+import java.util.Arrays;
import java.util.StringTokenizer;
/**
@@ -58,6 +59,10 @@ public static boolean isNullOrEmpty(CharSequence value) {
* @since 4.0.0
*/
public static String join(String separator, String[] strings) {
+ return join(separator, Arrays.asList(strings));
+ }
+
+ public static String join(String separator, Iterable strings) {
StringBuilder sb = new StringBuilder();
int end = 0;
for (String s : strings) {
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 ca3a4f17d..9a2a51e46 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
@@ -21,6 +21,7 @@
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.exceptions.ValidationException;
+import java.util.Arrays;
import java.util.Collection;
import static org.dizitart.no2.common.util.ObjectUtils.convertToObjectArray;
@@ -72,6 +73,12 @@ public static void notEmpty(Collection> value, String message) {
}
}
+ public static void notEmpty(T[] value, String message) {
+ if (value.length == 0) {
+ throw new ValidationException(message);
+ }
+ }
+
/**
* Validates if an object is `null`.
*
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/EqualsFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/EqualsFilter.java
index ec6807b04..12880f5e9 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/EqualsFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/EqualsFilter.java
@@ -45,10 +45,10 @@ protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
if (getValue() == null || getValue() instanceof Comparable) {
- if (getIndexer() instanceof ComparableIndexer) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findEqual(getCollectionName(), getField(), (Comparable) getValue());
- } else if (getIndexer() instanceof TextIndexer && getValue() instanceof String) {
+ } else if (getNitriteIndexer() instanceof TextIndexer && getValue() instanceof String) {
// eq filter is not compatible with TextIndexer
setIsFieldIndexed(false);
} else {
@@ -83,7 +83,7 @@ public boolean apply(Pair element) {
@Override
public void setIsFieldIndexed(Boolean isFieldIndexed) {
- if (!(getIndexer() instanceof TextIndexer && getValue() instanceof String)) {
+ if (!(getNitriteIndexer() instanceof TextIndexer && getValue() instanceof String)) {
super.setIsFieldIndexed(isFieldIndexed);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/GreaterEqualFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/GreaterEqualFilter.java
index 73c5a8802..ab58d2440 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/GreaterEqualFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/GreaterEqualFilter.java
@@ -41,8 +41,8 @@ class GreaterEqualFilter extends ComparisonFilter {
protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findGreaterEqual(getCollectionName(), getField(), (Comparable) getValue());
} else {
if (getValue() instanceof Comparable) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/GreaterThanFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/GreaterThanFilter.java
index 58681e9b4..f4b4e5ff3 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/GreaterThanFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/GreaterThanFilter.java
@@ -41,8 +41,8 @@ protected GreaterThanFilter(String field, Comparable> value) {
protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findGreaterThan(getCollectionName(), getField(), (Comparable) getValue());
} else {
if (getValue() instanceof Comparable) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/InFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/InFilter.java
index c450e9bee..a46cdd211 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/InFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/InFilter.java
@@ -49,8 +49,8 @@ protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && comparableSet != null) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && comparableSet != null) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findIn(getCollectionName(), getField(), comparableSet);
} else {
if (comparableSet != null && !comparableSet.isEmpty()) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/IndexAwareFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/IndexAwareFilter.java
index 195291566..c7f051ba2 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/IndexAwareFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/IndexAwareFilter.java
@@ -22,7 +22,7 @@
import lombok.ToString;
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
-import org.dizitart.no2.index.Indexer;
+import org.dizitart.no2.index.NitriteIndexer;
import org.dizitart.no2.store.NitriteMap;
import java.util.Set;
@@ -40,7 +40,7 @@ public abstract class IndexAwareFilter extends FieldBasedFilter {
private Boolean onIdField = false;
@Getter @Setter
- private Indexer indexer;
+ private NitriteIndexer nitriteIndexer;
private Set indexedIdSet;
private Set idSet;
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/IndexedQuerySupport.java b/nitrite/src/main/java/org/dizitart/no2/filters/IndexedQuerySupport.java
new file mode 100644
index 000000000..75f9c97a2
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/IndexedQuerySupport.java
@@ -0,0 +1,28 @@
+package org.dizitart.no2.filters;
+
+import org.dizitart.no2.NitriteConfig;
+import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.RecordStream;
+import org.dizitart.no2.index.ComparableIndexer;
+import org.dizitart.no2.store.NitriteMap;
+
+/**
+ * @author Anindya Chatterjee
+ */
+public class IndexedQuerySupport {
+ private ComparableIndexer comparableIndexer;
+
+ public IndexedQuerySupport(ComparableIndexer comparableIndexer) {
+ this.comparableIndexer = comparableIndexer;
+ }
+
+ public RecordStream findByFilter(NitriteMap, ?> indexMap, NitriteFilter filter, NitriteConfig nitriteConfig) {
+
+ return null;
+ }
+
+ public FieldValues calculateFieldValues(NitriteFilter filter) {
+
+ }
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/LesserEqualFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/LesserEqualFilter.java
index 8c5a98369..7b5af2aa6 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/LesserEqualFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/LesserEqualFilter.java
@@ -41,8 +41,8 @@ class LesserEqualFilter extends ComparisonFilter {
protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findLesserEqual(getCollectionName(), getField(), (Comparable) getValue());
} else {
if (getValue() instanceof Comparable) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/LesserThanFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/LesserThanFilter.java
index d3ad9ec68..f99397e92 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/LesserThanFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/LesserThanFilter.java
@@ -41,8 +41,8 @@ class LesserThanFilter extends ComparisonFilter {
protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && getValue() instanceof Comparable) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findLesserThan(getCollectionName(), getField(), (Comparable) getValue());
} else {
if (getValue() instanceof Comparable) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/NotEqualsFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/NotEqualsFilter.java
index d2cd71f8a..a5d57ab77 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/NotEqualsFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/NotEqualsFilter.java
@@ -29,10 +29,10 @@ protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
if (getValue() == null || getValue() instanceof Comparable) {
- if (getIndexer() instanceof ComparableIndexer) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findNotEqual(getCollectionName(), getField(), (Comparable) getValue());
- } else if (getIndexer() instanceof TextIndexer && getValue() instanceof String) {
+ } else if (getNitriteIndexer() instanceof TextIndexer && getValue() instanceof String) {
// notEq filter is not compatible with TextIndexer
setIsFieldIndexed(false);
} else {
@@ -67,7 +67,7 @@ public boolean apply(Pair element) {
@Override
public void setIsFieldIndexed(Boolean isFieldIndexed) {
- if (!(getIndexer() instanceof TextIndexer && getValue() instanceof String)) {
+ if (!(getNitriteIndexer() instanceof TextIndexer && getValue() instanceof String)) {
super.setIsFieldIndexed(isFieldIndexed);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/NotInFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/NotInFilter.java
index 5cd107c1f..1c80c7eb7 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/NotInFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/NotInFilter.java
@@ -49,8 +49,8 @@ protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof ComparableIndexer && comparableSet != null) {
- ComparableIndexer comparableIndexer = (ComparableIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof ComparableIndexer && comparableSet != null) {
+ ComparableIndexer comparableIndexer = (ComparableIndexer) getNitriteIndexer();
idSet = comparableIndexer.findNotIn(getCollectionName(), getField(), comparableSet);
} else {
if (comparableSet != null && !comparableSet.isEmpty()) {
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/QueryOptimizer.java b/nitrite/src/main/java/org/dizitart/no2/filters/QueryOptimizer.java
new file mode 100644
index 000000000..8a4ef3553
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/QueryOptimizer.java
@@ -0,0 +1,61 @@
+package org.dizitart.no2.filters;
+
+import org.dizitart.no2.NitriteConfig;
+import org.dizitart.no2.collection.Document;
+import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.collection.operation.FindOptions;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.RecordStream;
+import org.dizitart.no2.common.tuples.Pair;
+import org.dizitart.no2.index.BaseNitriteIndexer;
+import org.dizitart.no2.index.IndexDescriptor;
+import org.dizitart.no2.store.NitriteMap;
+
+/**
+ * @author Anindya Chatterjee
+ */
+public class QueryOptimizer {
+ private BaseNitriteIndexer nitriteIndexer;
+ private NitriteConfig nitriteConfig;
+
+ public RecordStream> findOptimizedStream(Filter filter,
+ FindOptions findOptions) {
+ if (filter == null) {
+ return findOptimizedStreamByOption(findOptions);
+ }
+
+ // 1. AND
+ // 2. OR (AND)
+ // 3. Union stream (for OR call recursively this method)
+
+ if (filter instanceof AndFilter) {
+ AndFilter andFilter = (AndFilter) filter;
+ FieldValues fieldValues = decompose(andFilter);
+ IndexDescriptor descriptor = findSuitableIndex(fieldValues);
+
+ if (nitriteIndexer.isCompoundIndex(descriptor)) {
+ NitriteMap, ?> indexMap = nitriteIndexer.getCompoundIndexMap(descriptor,
+ nitriteConfig.getNitriteStore(), fieldValues.getFirstValue().getClass());
+ }
+ }
+ }
+
+ private RecordStream> findOptimizedStreamByOption(FindOptions findOptions) {
+ return null;
+ }
+
+ private FieldValues decompose(AndFilter filter) {
+ FieldValues fieldValues = new FieldValues();
+
+ Filter lhs = filter.getLhs();
+ Filter rhs = filter.getRhs();
+
+ if (lhs instanceof ComparisonFilter) {
+
+ }
+ }
+
+ private IndexDescriptor findSuitableIndex(FieldValues fieldValues) {
+ return null;
+ }
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/filters/TextFilter.java b/nitrite/src/main/java/org/dizitart/no2/filters/TextFilter.java
index 2effd4ec8..bc5186bd3 100644
--- a/nitrite/src/main/java/org/dizitart/no2/filters/TextFilter.java
+++ b/nitrite/src/main/java/org/dizitart/no2/filters/TextFilter.java
@@ -38,8 +38,8 @@ class TextFilter extends StringFilter {
protected Set findIndexedIdSet() {
Set idSet = new LinkedHashSet<>();
if (getIsFieldIndexed()) {
- if (getIndexer() instanceof TextIndexer) {
- TextIndexer textIndexer = (TextIndexer) getIndexer();
+ if (getNitriteIndexer() instanceof TextIndexer) {
+ TextIndexer textIndexer = (TextIndexer) getNitriteIndexer();
idSet = textIndexer.findText(getCollectionName(), getField(), getStringValue());
} else {
throw new FilterException(getField() + " is not full-text indexed");
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/BaseNitriteIndexer.java b/nitrite/src/main/java/org/dizitart/no2/index/BaseNitriteIndexer.java
new file mode 100644
index 000000000..6f5ea5768
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/index/BaseNitriteIndexer.java
@@ -0,0 +1,62 @@
+package org.dizitart.no2.index;
+
+import org.dizitart.no2.NitriteConfig;
+import org.dizitart.no2.common.UnknownType;
+import org.dizitart.no2.store.NitriteMap;
+import org.dizitart.no2.store.NitriteStore;
+
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import static org.dizitart.no2.common.Constants.INDEX_PREFIX;
+import static org.dizitart.no2.common.Constants.INTERNAL_NAME_SEPARATOR;
+
+/**
+ * @author Anindya Chatterjee
+ */
+public abstract class BaseNitriteIndexer implements NitriteIndexer {
+
+ @Override
+ public void dropIndex(IndexDescriptor indexDescriptor, NitriteConfig nitriteConfig) {
+ NitriteMap, ?> indexMap;
+ if (isCompoundIndex(indexDescriptor)) {
+ indexMap = getCompoundIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
+ } else {
+ indexMap = getSimpleIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
+ }
+ indexMap.clear();
+ indexMap.drop();
+ }
+
+ public boolean isCompoundIndex(IndexDescriptor indexDescriptor) {
+ return indexDescriptor.getFields().getFieldNames().size() > 1;
+ }
+
+ @SuppressWarnings("rawtypes")
+ public NitriteMap> getSimpleIndexMap(IndexDescriptor indexDescriptor,
+ NitriteStore> nitriteStore,
+ Class> keyType) {
+ String mapName = getIndexMapName(indexDescriptor);
+ return nitriteStore.openMap(mapName, keyType, ConcurrentSkipListSet.class);
+ }
+
+ @SuppressWarnings("rawtypes")
+ public NitriteMap> getCompoundIndexMap(IndexDescriptor indexDescriptor,
+ NitriteStore> nitriteStore,
+ Class> keyType) {
+ String mapName = getIndexMapName(indexDescriptor);
+ return nitriteStore.openMap(mapName, keyType, ConcurrentSkipListMap.class);
+ }
+
+ protected String getIndexMapName(IndexDescriptor indexDescriptor) {
+ return INDEX_PREFIX +
+ INTERNAL_NAME_SEPARATOR +
+ indexDescriptor.getCollectionName() +
+ INTERNAL_NAME_SEPARATOR +
+ indexDescriptor.getFields().getEncodedName() +
+ INTERNAL_NAME_SEPARATOR +
+ getIndexType();
+ }
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/ComparableIndexer.java b/nitrite/src/main/java/org/dizitart/no2/index/ComparableIndexer.java
index 7eb7f3c30..e02297111 100644
--- a/nitrite/src/main/java/org/dizitart/no2/index/ComparableIndexer.java
+++ b/nitrite/src/main/java/org/dizitart/no2/index/ComparableIndexer.java
@@ -17,304 +17,401 @@
package org.dizitart.no2.index;
import org.dizitart.no2.NitriteConfig;
-import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
-import org.dizitart.no2.common.UnknownType;
+import org.dizitart.no2.common.*;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.common.util.Iterables;
+import org.dizitart.no2.exceptions.FilterException;
+import org.dizitart.no2.exceptions.IndexingException;
import org.dizitart.no2.exceptions.UniqueConstraintException;
import org.dizitart.no2.exceptions.ValidationException;
+import org.dizitart.no2.filters.Filter;
+import org.dizitart.no2.filters.IndexedQuerySupport;
+import org.dizitart.no2.filters.NitriteFilter;
+import org.dizitart.no2.store.IndexCatalog;
import org.dizitart.no2.store.NitriteMap;
import org.dizitart.no2.store.NitriteStore;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.Set;
+import java.util.*;
+import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
+import static org.dizitart.no2.common.util.Iterables.getElementType;
import static org.dizitart.no2.common.util.ObjectUtils.convertToObjectArray;
-import static org.dizitart.no2.common.util.ObjectUtils.deepEquals;
-import static org.dizitart.no2.common.util.ValidationUtils.*;
+import static org.dizitart.no2.common.util.ValidationUtils.validateArrayIndexField;
+import static org.dizitart.no2.common.util.ValidationUtils.validateIterableIndexField;
/**
* @author Anindya Chatterjee
*/
@SuppressWarnings("rawtypes")
-public abstract class ComparableIndexer implements Indexer {
- private NitriteStore> nitriteStore;
+public abstract class ComparableIndexer extends BaseNitriteIndexer {
+ protected IndexedQuerySupport querySupport;
+
+ public ComparableIndexer() {
+ querySupport = new IndexedQuerySupport(this);
+ }
abstract boolean isUnique();
- public ComparableIndexer clone() throws CloneNotSupportedException {
- return (ComparableIndexer) super.clone();
+ @Override
+ public void initialize(NitriteConfig nitriteConfig) {
}
@Override
- public void initialize(NitriteConfig nitriteConfig) {
- this.nitriteStore = nitriteConfig.getNitriteStore();
+ public RecordStream findByFilter(String collectionName, Filter filter, NitriteConfig nitriteConfig) {
+ if (filter instanceof NitriteFilter) {
+ NitriteFilter nitriteFilter = (NitriteFilter) filter;
+ IndexCatalog indexCatalog = nitriteConfig.getNitriteStore().getIndexCatalog();
+ Collection descriptors = indexCatalog.listIndexDescriptors(collectionName);
+
+
+ FieldValues fieldValues = querySupport.calculateFieldValues(nitriteFilter);
+ IndexDescriptor descriptor = new IndexDescriptor(getIndexType(), fieldValues.getFields(), collectionName);
+
+ NitriteMap, ?> indexMap = findSuitableIndexMap(descriptor, fieldValues, nitriteConfig.getNitriteStore());
+
+
+ return querySupport.findByFilter(indexMap, nitriteFilter, nitriteConfig);
+ } else {
+ throw new FilterException(filter.getClass().getName() + " is not supported");
+ }
}
+ //region Write Index
+
@Override
- public void writeIndex(NitriteMap collection, NitriteId nitriteId, String field, Object fieldValue) {
- validateIndexField(fieldValue, field);
- addIndexEntry(collection.getName(), nitriteId, field, fieldValue);
+ public void writeIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ if (isCompoundIndex(indexDescriptor)) {
+ writeCompoundIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ } else {
+ writeSimpleIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ }
}
@Override
- public void removeIndex(NitriteMap collection, NitriteId nitriteId, String field, Object fieldValue) {
- validateIndexField(fieldValue, field);
- NitriteMap> indexMap = null;
-
- if (fieldValue == null) {
- indexMap = getIndexMap(collection.getName(), field, UnknownType.class);
- removeElementFromIndexMap(indexMap, nitriteId, field, null);
- } else if (fieldValue instanceof Comparable) {
- indexMap = getIndexMap(collection.getName(), field, fieldValue.getClass());
- removeElementFromIndexMap(indexMap, nitriteId, field, (Comparable) fieldValue);
- } else if (fieldValue.getClass().isArray()) {
- Object[] array = convertToObjectArray(fieldValue);
+ public void removeIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ if (isCompoundIndex(indexDescriptor)) {
+ removeCompoundIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ } else {
+ removeSimpleIndexEntry(indexDescriptor, fieldValues, nitriteConfig);
+ }
+ }
+
+ private void writeCompoundIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ Fields fields = fieldValues.getFields();
+ List fieldNames = fields.getFieldNames();
+
+ String firstField = fieldNames.get(0);
+ Object firstValue = fieldValues.get(firstField);
+
+ // NOTE: only first field can have array or iterable value, subsequent fields can not
+ validateIndexField(firstValue, firstField);
+
+ if (firstValue == null) {
+ NitriteMap> indexMap
+ = getCompoundIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
+
+ addCompoundIndexElement(indexMap, fieldValues, null);
+ } else if (firstValue instanceof Comparable) {
+ NitriteMap> indexMap
+ = getCompoundIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), firstValue.getClass());
+
+ addCompoundIndexElement(indexMap, fieldValues, (Comparable) firstValue);
+ } else if (firstValue.getClass().isArray()) {
+ Object[] array = convertToObjectArray(firstValue);
+ NitriteMap> indexMap = getCompoundIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), array.getClass().getComponentType());
for (Object item : array) {
- if (indexMap == null) {
- indexMap = getIndexMap(collection.getName(), field, item.getClass());
- }
- removeElementFromIndexMap(indexMap, nitriteId, field, (Comparable) item);
+ addCompoundIndexElement(indexMap, fieldValues, (Comparable) item);
}
- } else if (fieldValue instanceof Iterable) {
- Iterable iterable = (Iterable) fieldValue;
+ } else if (firstValue instanceof Iterable) {
+ Iterable iterable = (Iterable) firstValue;
+ NitriteMap> indexMap = getCompoundIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), getElementType(iterable));
+
for (Object item : iterable) {
- if (indexMap == null) {
- indexMap = getIndexMap(collection.getName(), field, item.getClass());
- }
- removeElementFromIndexMap(indexMap, nitriteId, field, (Comparable) item);
+ addCompoundIndexElement(indexMap, fieldValues, (Comparable) item);
}
}
}
- @Override
- public void updateIndex(NitriteMap collection, NitriteId nitriteId, String field, Object newValue, Object oldValue) {
- validateIndexField(newValue, field);
- validateIndexField(oldValue, field);
- addIndexEntry(collection.getName(), nitriteId, field, newValue);
- removeIndex(collection, nitriteId, field, oldValue);
- }
+ private void writeSimpleIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ Fields fields = fieldValues.getFields();
+ List fieldNames = fields.getFieldNames();
- @Override
- public void dropIndex(NitriteMap collection, String field) {
- // no action required
- }
+ String firstField = fieldNames.get(0);
+ Object element = fieldValues.get(firstField);
- public Set findEqual(String collectionName, String field, Comparable value) {
- NitriteMap> indexMap =
- value != null ? getIndexMap(collectionName, field, value.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
+ if (element == null) {
+ NitriteMap> indexMap
+ = getSimpleIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
- Set resultSet = null;
- if (indexMap != null) {
- resultSet = indexMap.get(value);
- }
+ addSimpleIndexElement(indexMap, fieldValues, null);
+ } else if (element instanceof Comparable) {
+ NitriteMap> indexMap
+ = getSimpleIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), element.getClass());
- if (resultSet == null) {
- resultSet = new LinkedHashSet<>();
- }
- return resultSet;
- }
+ addSimpleIndexElement(indexMap, fieldValues, (Comparable) element);
+ } else if (element.getClass().isArray()) {
+ Object[] array = convertToObjectArray(element);
+ NitriteMap> indexMap = getSimpleIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), array.getClass().getComponentType());
- public Set findNotEqual(String collectionName, String field, Comparable value) {
- NitriteMap> indexMap =
- value != null ? getIndexMap(collectionName, field, value.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
+ for (Object item : array) {
+ addSimpleIndexElement(indexMap, fieldValues, (Comparable) item);
+ }
+ } else if (element instanceof Iterable) {
+ Iterable iterable = (Iterable) element;
+ NitriteMap> indexMap = getSimpleIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), getElementType(iterable));
- Set resultSet = new LinkedHashSet<>();
- if (indexMap != null) {
- for (Pair> entry : indexMap.entries()) {
- if (!deepEquals(entry.getFirst(), value)) {
- resultSet.addAll(entry.getSecond());
- }
+ for (Object item : iterable) {
+ addSimpleIndexElement(indexMap, fieldValues, (Comparable) item);
}
}
-
- return resultSet;
}
- public Set findGreaterThan(String collectionName, String field, Comparable comparable) {
- Set resultSet = new LinkedHashSet<>();
- NitriteMap> indexMap =
- comparable != null ? getIndexMap(collectionName, field, comparable.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
-
- if (indexMap != null) {
- Comparable higherKey = indexMap.higherKey(comparable);
- while (higherKey != null) {
- resultSet.addAll(indexMap.get(higherKey));
- higherKey = indexMap.higherKey(higherKey);
- }
+ private void addCompoundIndexElement(NitriteMap> indexMap,
+ FieldValues fieldValues, Comparable element) {
+ NavigableMap, ?> subMap = indexMap.get(element);
+ if (subMap == null) {
+ SortOrder sortOrder = fieldValues.getFields().getFirstKey().getSecond();
+ subMap = sortOrder == SortOrder.Ascending ? new ConcurrentSkipListMap<>()
+ : new ConcurrentSkipListMap<>(Collections.reverseOrder());
}
- return resultSet;
+ populateSubMap(subMap, fieldValues, 1);
+ indexMap.put(element, subMap);
}
- public Set findGreaterEqual(String collectionName, String field, Comparable comparable) {
- Set resultSet = new LinkedHashSet<>();
- NitriteMap> indexMap =
- comparable != null ? getIndexMap(collectionName, field, comparable.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
-
- if (indexMap != null) {
- Comparable ceilingKey = indexMap.ceilingKey(comparable);
- while (ceilingKey != null) {
- resultSet.addAll(indexMap.get(ceilingKey));
- ceilingKey = indexMap.higherKey(ceilingKey);
+ @SuppressWarnings("unchecked")
+ private void populateSubMap(NavigableMap subMap, FieldValues fieldValues, int startIndex) {
+ for (int i = startIndex; i < fieldValues.getValues().size(); i++) {
+ Pair pair = fieldValues.getValues().get(i);
+ Object value = pair.getSecond();
+ if (value == null) {
+ value = DBNull.getInstance();
}
- }
- return resultSet;
- }
+ if (!(value instanceof Comparable)) {
+ throw new IndexingException(value + " is not comparable");
+ }
- public Set findLesserThan(String collectionName, String field, Comparable comparable) {
- Set resultSet = new LinkedHashSet<>();
- NitriteMap> indexMap =
- comparable != null ? getIndexMap(collectionName, field, comparable.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
-
- if (indexMap != null) {
- Comparable lowerKey = indexMap.lowerKey(comparable);
- while (lowerKey != null) {
- resultSet.addAll(indexMap.get(lowerKey));
- lowerKey = indexMap.lowerKey(lowerKey);
+ if (i == fieldValues.getValues().size() - 1) {
+ NavigableSet nitriteIds = (NavigableSet) subMap.get(value);
+ nitriteIds = addNitriteIds(nitriteIds, fieldValues);
+ subMap.put(value, nitriteIds);
+ } else {
+ NavigableMap subMap2 = (NavigableMap) subMap.get(value);
+ if (subMap2 == null) {
+ SortOrder sortOrder = fieldValues.getFields().getSortOrder(pair.getFirst());
+ subMap2 = sortOrder == SortOrder.Ascending ? new ConcurrentSkipListMap<>()
+ : new ConcurrentSkipListMap<>(Collections.reverseOrder());
+ }
+
+ populateSubMap(subMap2, fieldValues, startIndex + 1);
+ subMap.put(value, subMap2);
}
}
+ }
- return resultSet;
+ @SuppressWarnings("unchecked")
+ private void addSimpleIndexElement(NitriteMap> indexMap,
+ FieldValues fieldValues, Comparable element) {
+ NavigableSet nitriteIds = (NavigableSet) indexMap.get(element);
+ nitriteIds = addNitriteIds(nitriteIds, fieldValues);
+ indexMap.put(element, nitriteIds);
}
- public Set findLesserEqual(String collectionName, String field, Comparable comparable) {
- Set resultSet = new LinkedHashSet<>();
- NitriteMap> indexMap =
- comparable != null ? getIndexMap(collectionName, field, comparable.getClass())
- : getIndexMap(collectionName, field, UnknownType.class);
-
- if (indexMap != null) {
- Comparable floorKey = indexMap.floorKey(comparable);
- while (floorKey != null) {
- resultSet.addAll(indexMap.get(floorKey));
- floorKey = indexMap.lowerKey(floorKey);
- }
+ private NavigableSet addNitriteIds(NavigableSet nitriteIds, FieldValues fieldValues) {
+ if (nitriteIds == null) {
+ nitriteIds = new ConcurrentSkipListSet<>();
}
- return resultSet;
+ if (isUnique() && nitriteIds.size() == 1
+ && !nitriteIds.contains(fieldValues.getNitriteId())) {
+ // if key is already exists for unique type, throw error
+ throw new UniqueConstraintException("unique key constraint violation for " + fieldValues.getFields());
+ }
+
+ nitriteIds.add(fieldValues.getNitriteId());
+ return nitriteIds;
}
- public Set findIn(String collectionName, String field, Collection> values) {
- notNull(values, "values cannot be null");
- notEmpty(values, "values cannot be empty");
+ private void removeCompoundIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ Fields fields = fieldValues.getFields();
+ List fieldNames = fields.getFieldNames();
- Set resultSet = new LinkedHashSet<>();
- Class> type = Iterables.firstOrNull(values).getClass();
- NitriteMap> indexMap = getIndexMap(collectionName, field, type);
+ String firstField = fieldNames.get(0);
+ Object firstValue = fieldValues.get(firstField);
- if (indexMap != null) {
- for (Comparable comparable : indexMap.keySet()) {
- if (values.contains(comparable)) {
- resultSet.addAll(indexMap.get(comparable));
- }
- }
- }
+ // NOTE: only first field can have array or iterable value, subsequent fields can not
+ validateIndexField(firstValue, firstField);
- return resultSet;
- }
+ if (firstValue == null) {
+ NitriteMap> indexMap
+ = getCompoundIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
- public Set findNotIn(String collectionName, String field, Collection> values) {
- notNull(values, "values cannot be null");
+ removeCompoundIndexElement(indexMap, fieldValues, null);
+ } else if (firstValue instanceof Comparable) {
+ NitriteMap> indexMap
+ = getCompoundIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), firstValue.getClass());
- Set resultSet = new LinkedHashSet<>();
- Class> type = Iterables.firstOrNull(values).getClass();
- NitriteMap> indexMap = getIndexMap(collectionName, field, type);
+ removeCompoundIndexElement(indexMap, fieldValues, (Comparable) firstValue);
+ } else if (firstValue.getClass().isArray()) {
+ Object[] array = convertToObjectArray(firstValue);
+ NitriteMap> indexMap = getCompoundIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), array.getClass().getComponentType());
- if (indexMap != null) {
- for (Comparable comparable : indexMap.keySet()) {
- if (!values.contains(comparable)) {
- resultSet.addAll(indexMap.get(comparable));
- }
+ for (Object item : array) {
+ removeCompoundIndexElement(indexMap, fieldValues, (Comparable) item);
}
- }
-
- return resultSet;
- }
+ } else if (firstValue instanceof Iterable) {
+ Iterable iterable = (Iterable) firstValue;
+ NitriteMap> indexMap = getCompoundIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), getElementType(iterable));
- private void validateIndexField(Object value, String field) {
- if (value == null) return;
- if (value instanceof Iterable) {
- validateIterableIndexField((Iterable) value, field);
- } else if (value.getClass().isArray()) {
- validateArrayIndexField(value, field);
- } else {
- if (!(value instanceof Comparable)) {
- throw new ValidationException(value + " is not comparable");
+ for (Object item : iterable) {
+ removeCompoundIndexElement(indexMap, fieldValues, (Comparable) item);
}
}
}
- private void addIndexEntry(String collectionName, NitriteId id, String field, Object element) {
- NitriteMap> indexMap
- = getIndexMap(collectionName, field, UnknownType.class);
+ private void removeSimpleIndexEntry(IndexDescriptor indexDescriptor,
+ FieldValues fieldValues,
+ NitriteConfig nitriteConfig) {
+ Fields fields = fieldValues.getFields();
+ List fieldNames = fields.getFieldNames();
+
+ String firstField = fieldNames.get(0);
+ Object element = fieldValues.get(firstField);
if (element == null) {
- addElementToIndexMap(indexMap, id, field, null);
+ NitriteMap> indexMap
+ = getSimpleIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), UnknownType.class);
+
+ removeSimpleIndexElement(indexMap, fieldValues, null);
} else if (element instanceof Comparable) {
- addElementToIndexMap(indexMap, id, field, (Comparable) element);
+ NitriteMap> indexMap
+ = getSimpleIndexMap(indexDescriptor, nitriteConfig.getNitriteStore(), element.getClass());
+
+ removeSimpleIndexElement(indexMap, fieldValues, (Comparable) element);
} else if (element.getClass().isArray()) {
Object[] array = convertToObjectArray(element);
+ NitriteMap> indexMap = getSimpleIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), array.getClass().getComponentType());
+
for (Object item : array) {
- addElementToIndexMap(indexMap, id, field, (Comparable) item);
+ removeSimpleIndexElement(indexMap, fieldValues, (Comparable) item);
}
} else if (element instanceof Iterable) {
Iterable iterable = (Iterable) element;
+ NitriteMap> indexMap = getSimpleIndexMap(indexDescriptor,
+ nitriteConfig.getNitriteStore(), getElementType(iterable));
+
for (Object item : iterable) {
- addElementToIndexMap(indexMap, id, field, (Comparable) item);
+ removeSimpleIndexElement(indexMap, fieldValues, (Comparable) item);
}
}
}
- private void addElementToIndexMap(NitriteMap> indexMap,
- NitriteId id, String field, Comparable element) {
- // create the nitriteId list associated with the value
- ConcurrentSkipListSet nitriteIdList
- = indexMap.get(element);
-
- if (nitriteIdList == null) {
- nitriteIdList = new ConcurrentSkipListSet<>();
+ @SuppressWarnings("unchecked")
+ private void removeSimpleIndexElement(NitriteMap> indexMap,
+ FieldValues fieldValues, Comparable element) {
+ NavigableSet nitriteIds = (NavigableSet) indexMap.get(element);
+ if (nitriteIds != null && !nitriteIds.isEmpty()) {
+ nitriteIds.remove(fieldValues.getNitriteId());
+ if (nitriteIds.size() == 0) {
+ indexMap.remove(element);
+ } else {
+ indexMap.put(element, nitriteIds);
+ }
}
+ }
- if (isUnique() && nitriteIdList.size() == 1
- && !nitriteIdList.contains(id)) {
- // if key is already exists for unique type, throw error
- throw new UniqueConstraintException("unique key constraint violation for " + field);
+ private void removeCompoundIndexElement(NitriteMap> indexMap,
+ FieldValues fieldValues, Comparable element) {
+ NavigableMap, ?> subMap = indexMap.get(element);
+ if (subMap != null && !subMap.isEmpty()) {
+ deleteFromSubMap(subMap, fieldValues, 1);
+ indexMap.put(element, subMap);
}
-
- nitriteIdList.add(id);
- indexMap.put(element, nitriteIdList);
}
- private void removeElementFromIndexMap(NitriteMap> indexMap,
- NitriteId nitriteId, String field, Comparable element) {
- // create the nitrite list associated with the value
- ConcurrentSkipListSet nitriteIdList = indexMap.get(element);
- if (nitriteIdList != null && !nitriteIdList.isEmpty()) {
- nitriteIdList.remove(nitriteId);
- if (nitriteIdList.size() == 0) {
- indexMap.remove(element);
+ @SuppressWarnings("unchecked")
+ private void deleteFromSubMap(NavigableMap subMap, FieldValues fieldValues, int startIndex) {
+ for (int i = startIndex; i < fieldValues.getValues().size(); i++) {
+ Pair pair = fieldValues.getValues().get(i);
+ Object value = pair.getSecond();
+ if (value == null) {
+ value = DBNull.getInstance();
+ }
+
+ if (!(value instanceof Comparable)) {
+ continue;
+ }
+
+ if (i == fieldValues.getValues().size() - 1) {
+ NavigableSet nitriteIds = (NavigableSet) subMap.get(value);
+ nitriteIds = removeNitriteIds(nitriteIds, fieldValues);
+ if (nitriteIds == null || nitriteIds.isEmpty()) {
+ subMap.remove(value);
+ } else {
+ subMap.put(value, nitriteIds);
+ }
} else {
- indexMap.put(element, nitriteIdList);
+ NavigableMap subMap2 = (NavigableMap) subMap.get(value);
+ if (subMap2 == null) {
+ continue;
+ }
+
+ deleteFromSubMap(subMap2, fieldValues, startIndex + 1);
+ subMap.put(value, subMap2);
}
}
}
- @SuppressWarnings("rawtypes")
- private NitriteMap> getIndexMap(
- String collectionName, String field, Class> keyType) {
+ private NavigableSet removeNitriteIds(NavigableSet nitriteIds, FieldValues fieldValues) {
+ if (nitriteIds != null && !nitriteIds.isEmpty()) {
+ nitriteIds.remove(fieldValues.getNitriteId());
+ }
+ return nitriteIds;
+ }
+
+ private void validateIndexField(Object value, String field) {
+ if (value == null) return;
+ if (value instanceof Iterable) {
+ validateIterableIndexField((Iterable) value, field);
+ } else if (value.getClass().isArray()) {
+ validateArrayIndexField(value, field);
+ } else {
+ if (!(value instanceof Comparable)) {
+ throw new ValidationException(value + " is not comparable");
+ }
+ }
+ }
- String mapName = getIndexMapName(collectionName, field);
- return nitriteStore.openMap(mapName, keyType, ConcurrentSkipListSet.class);
+ //endregion
+
+ private NitriteMap, ?> findSuitableIndexMap(IndexDescriptor descriptor,
+ FieldValues fieldValues,
+ NitriteStore> nitriteStore) {
+ // get all indices of a collection
+ // find the suitable index (prefix included)
+ // find the index map
+ // get value by prefix using filter (if compound)
+ // get value by filter (if simple)
+ return null;
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/IndexEntry.java b/nitrite/src/main/java/org/dizitart/no2/index/IndexDescriptor.java
similarity index 75%
rename from nitrite/src/main/java/org/dizitart/no2/index/IndexEntry.java
rename to nitrite/src/main/java/org/dizitart/no2/index/IndexDescriptor.java
index 99ee89858..e9bee5136 100644
--- a/nitrite/src/main/java/org/dizitart/no2/index/IndexEntry.java
+++ b/nitrite/src/main/java/org/dizitart/no2/index/IndexDescriptor.java
@@ -18,6 +18,7 @@
import lombok.*;
import org.dizitart.no2.collection.NitriteCollection;
+import org.dizitart.no2.common.Fields;
import java.io.IOException;
import java.io.ObjectInputStream;
@@ -32,12 +33,13 @@
*
* @author Anindya Chatterjee
* @see NitriteCollection#createIndex(String, IndexOptions)
+ * @see NitriteCollection#createIndex(Fields, IndexOptions)
* @since 1.0
*/
@ToString
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class IndexEntry implements Comparable, Serializable {
+public class IndexDescriptor implements Comparable, Serializable {
private static final long serialVersionUID = 1576690829L;
/**
@@ -50,12 +52,12 @@ public class IndexEntry implements Comparable, Serializable {
private String indexType;
/**
- * Gets the target field for the index.
+ * Gets the target fields for the index.
*
- * @return the target field.
+ * @return the target fields.
*/
@Getter
- private String field;
+ private Fields fields;
/**
* Gets the collection name.
@@ -69,36 +71,36 @@ public class IndexEntry implements Comparable, Serializable {
* Instantiates a new Index.
*
* @param indexType the index type
- * @param field the value
+ * @param fields the value
* @param collectionName the collection name
*/
- public IndexEntry(String indexType, String field, String collectionName) {
+ public IndexDescriptor(String indexType, Fields fields, String collectionName) {
notNull(indexType, "indexType cannot be null");
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
notNull(collectionName, "collectionName cannot be null");
notEmpty(collectionName, "collectionName cannot be empty");
this.indexType = indexType;
- this.field = field;
+ this.fields = fields;
this.collectionName = collectionName;
}
@Override
- public int compareTo(IndexEntry other) {
- String string = collectionName + field + indexType;
- String otherString = other.collectionName + other.field + other.indexType;
+ public int compareTo(IndexDescriptor other) {
+ String string = collectionName + fields + indexType;
+ String otherString = other.collectionName + other.fields + other.indexType;
return string.compareTo(otherString);
}
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.writeUTF(indexType);
- stream.writeUTF(field);
+ stream.writeObject(fields);
stream.writeUTF(collectionName);
}
- private void readObject(ObjectInputStream stream) throws IOException {
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
indexType = stream.readUTF();
- field = stream.readUTF();
+ fields = (Fields) stream.readObject();
collectionName = stream.readUTF();
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/IndexMeta.java b/nitrite/src/main/java/org/dizitart/no2/index/IndexMeta.java
index cb04a58ae..9729eccfa 100644
--- a/nitrite/src/main/java/org/dizitart/no2/index/IndexMeta.java
+++ b/nitrite/src/main/java/org/dizitart/no2/index/IndexMeta.java
@@ -36,18 +36,18 @@
public class IndexMeta implements Serializable {
private static final long serialVersionUID = 1576690663L;
- private IndexEntry indexEntry;
+ private IndexDescriptor indexDescriptor;
private String indexMap;
private AtomicBoolean isDirty;
private void writeObject(ObjectOutputStream stream) throws IOException {
- stream.writeObject(indexEntry);
+ stream.writeObject(indexDescriptor);
stream.writeUTF(indexMap);
stream.writeObject(isDirty);
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
- indexEntry = (IndexEntry) stream.readObject();
+ indexDescriptor = (IndexDescriptor) stream.readObject();
indexMap = stream.readUTF();
isDirty = (AtomicBoolean) stream.readObject();
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/Indexer.java b/nitrite/src/main/java/org/dizitart/no2/index/Indexer.java
deleted file mode 100644
index 1ced8e8f3..000000000
--- a/nitrite/src/main/java/org/dizitart/no2/index/Indexer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2017-2020. Nitrite author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.dizitart.no2.index;
-
-import org.dizitart.no2.collection.Document;
-import org.dizitart.no2.collection.NitriteId;
-import org.dizitart.no2.module.NitritePlugin;
-import org.dizitart.no2.store.NitriteMap;
-
-import static org.dizitart.no2.common.Constants.INDEX_PREFIX;
-import static org.dizitart.no2.common.Constants.INTERNAL_NAME_SEPARATOR;
-
-/**
- * @author Anindya Chatterjee.
- */
-public interface Indexer extends NitritePlugin, Cloneable {
- String getIndexType();
-
- void writeIndex(NitriteMap collection, NitriteId nitriteId, String field, Object fieldValue);
-
- void removeIndex(NitriteMap collection, NitriteId nitriteId, String field, Object fieldValue);
-
- void updateIndex(NitriteMap collection, NitriteId nitriteId, String field, Object newValue, Object oldValue);
-
- void dropIndex(NitriteMap collection, String field);
-
- Indexer clone() throws CloneNotSupportedException;
-
- default String getIndexMapName(String collectionName, String field) {
- return INDEX_PREFIX +
- INTERNAL_NAME_SEPARATOR +
- collectionName +
- INTERNAL_NAME_SEPARATOR +
- field +
- INTERNAL_NAME_SEPARATOR +
- getIndexType();
- }
-}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/NitriteIndexer.java b/nitrite/src/main/java/org/dizitart/no2/index/NitriteIndexer.java
new file mode 100644
index 000000000..d77b279ac
--- /dev/null
+++ b/nitrite/src/main/java/org/dizitart/no2/index/NitriteIndexer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2020. Nitrite author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dizitart.no2.index;
+
+import org.dizitart.no2.NitriteConfig;
+import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.common.FieldValues;
+import org.dizitart.no2.common.RecordStream;
+import org.dizitart.no2.filters.Filter;
+import org.dizitart.no2.module.NitritePlugin;
+
+/**
+ * @author Anindya Chatterjee.
+ */
+public interface NitriteIndexer extends NitritePlugin {
+ String getIndexType();
+
+ void dropIndex(IndexDescriptor indexDescriptor, NitriteConfig nitriteConfig);
+
+ void writeIndexEntry(IndexDescriptor indexDescriptor, FieldValues fieldValues, NitriteConfig nitriteConfig);
+
+ void removeIndexEntry(IndexDescriptor indexDescriptor, FieldValues fieldValues, NitriteConfig nitriteConfig);
+
+ RecordStream findByFilter(String collectionName, Filter filter, NitriteConfig nitriteConfig);
+}
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/NitriteTextIndexer.java b/nitrite/src/main/java/org/dizitart/no2/index/NitriteTextIndexer.java
index a73574964..d9083c4e6 100644
--- a/nitrite/src/main/java/org/dizitart/no2/index/NitriteTextIndexer.java
+++ b/nitrite/src/main/java/org/dizitart/no2/index/NitriteTextIndexer.java
@@ -19,6 +19,7 @@
import org.dizitart.no2.NitriteConfig;
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.exceptions.FilterException;
import org.dizitart.no2.exceptions.IndexingException;
@@ -117,8 +118,8 @@ public void updateIndex(NitriteMap collection, NitriteId ni
}
@Override
- public void dropIndex(NitriteMap collection, String field) {
- indexCatalog.dropIndexEntry(collection.getName(), field);
+ public void dropIndex(NitriteMap collection, Fields field) {
+ indexCatalog.dropIndexDescriptor(collection.getName(), field);
}
@Override
diff --git a/nitrite/src/main/java/org/dizitart/no2/index/TextIndexer.java b/nitrite/src/main/java/org/dizitart/no2/index/TextIndexer.java
index 0c11c7713..a7ba89d43 100644
--- a/nitrite/src/main/java/org/dizitart/no2/index/TextIndexer.java
+++ b/nitrite/src/main/java/org/dizitart/no2/index/TextIndexer.java
@@ -31,7 +31,7 @@
* @see FluentFilter#text(String)
* @since 1.0
*/
-public interface TextIndexer extends Indexer {
+public interface TextIndexer extends NitriteIndexer {
/**
* Finds matching text using full-text index.
*
diff --git a/nitrite/src/main/java/org/dizitart/no2/migration/commands/AddField.java b/nitrite/src/main/java/org/dizitart/no2/migration/commands/AddField.java
index db7c6fb48..39e7a40c4 100644
--- a/nitrite/src/main/java/org/dizitart/no2/migration/commands/AddField.java
+++ b/nitrite/src/main/java/org/dizitart/no2/migration/commands/AddField.java
@@ -5,7 +5,7 @@
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.migration.Generator;
/**
@@ -21,7 +21,7 @@ public class AddField extends BaseCommand implements Command {
public void execute(Nitrite nitrite) {
initialize(nitrite, collectionName);
- IndexEntry indexEntry = indexCatalog.findIndexEntry(collectionName, fieldName);
+ IndexDescriptor indexDescriptor = indexCatalog.findIndexDescriptor(collectionName, fieldName);
for (Pair pair : nitriteMap.entries()) {
Document document = pair.getSecond();
@@ -34,8 +34,8 @@ public void execute(Nitrite nitrite) {
nitriteMap.put(pair.getFirst(), document);
}
- if (indexEntry != null) {
- operations.createIndex(fieldName, indexEntry.getIndexType(), false);
+ if (indexDescriptor != null) {
+ operations.createIndex(fieldName, indexDescriptor.getIndexType(), false);
}
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/migration/commands/ChangeDataType.java b/nitrite/src/main/java/org/dizitart/no2/migration/commands/ChangeDataType.java
index 9c34d4bf7..cec45fdc0 100644
--- a/nitrite/src/main/java/org/dizitart/no2/migration/commands/ChangeDataType.java
+++ b/nitrite/src/main/java/org/dizitart/no2/migration/commands/ChangeDataType.java
@@ -5,7 +5,7 @@
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.migration.TypeConverter;
/**
@@ -31,9 +31,9 @@ public void execute(Nitrite nitrite) {
nitriteMap.put(entry.getFirst(), document);
}
- IndexEntry indexEntry = indexCatalog.findIndexEntry(collectionName, fieldName);
- if (indexEntry != null) {
- operations.rebuildIndex(indexEntry, false);
+ IndexDescriptor indexDescriptor = indexCatalog.findIndexDescriptor(collectionName, fieldName);
+ if (indexDescriptor != null) {
+ operations.rebuildIndex(indexDescriptor, false);
}
}
}
\ No newline at end of file
diff --git a/nitrite/src/main/java/org/dizitart/no2/migration/commands/DeleteField.java b/nitrite/src/main/java/org/dizitart/no2/migration/commands/DeleteField.java
index b9a4f0272..6e840351d 100644
--- a/nitrite/src/main/java/org/dizitart/no2/migration/commands/DeleteField.java
+++ b/nitrite/src/main/java/org/dizitart/no2/migration/commands/DeleteField.java
@@ -5,7 +5,7 @@
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
/**
* @author Anindya Chatterjee
@@ -19,14 +19,14 @@ public class DeleteField extends BaseCommand implements Command {
public void execute(Nitrite nitrite) {
initialize(nitrite, collectionName);
- IndexEntry indexEntry = indexCatalog.findIndexEntry(collectionName, fieldName);
+ IndexDescriptor indexDescriptor = indexCatalog.findIndexDescriptor(collectionName, fieldName);
for (Pair entry : nitriteMap.entries()) {
Document document = entry.getSecond();
document.remove(fieldName);
nitriteMap.put(entry.getFirst(), document);
}
- if (indexEntry != null) {
+ if (indexDescriptor != null) {
operations.dropIndex(fieldName);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/migration/commands/Rename.java b/nitrite/src/main/java/org/dizitart/no2/migration/commands/Rename.java
index 4092710b8..13bcfdca5 100644
--- a/nitrite/src/main/java/org/dizitart/no2/migration/commands/Rename.java
+++ b/nitrite/src/main/java/org/dizitart/no2/migration/commands/Rename.java
@@ -6,7 +6,7 @@
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.collection.operation.CollectionOperations;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.store.IndexCatalog;
import org.dizitart.no2.store.NitriteMap;
@@ -32,10 +32,10 @@ public void execute(Nitrite nitrite) {
}
IndexCatalog indexCatalog = nitrite.getStore().getIndexCatalog();
- Collection indexEntries = indexCatalog.listIndexEntries(oldName);
- for (IndexEntry indexEntry : indexEntries) {
- String field = indexEntry.getField();
- String indexType = indexEntry.getIndexType();
+ Collection indexEntries = indexCatalog.listIndexDescriptors(oldName);
+ for (IndexDescriptor indexDescriptor : indexEntries) {
+ String field = indexDescriptor.getFields();
+ String indexType = indexDescriptor.getIndexType();
newOperations.createIndex(field, indexType, false);
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/migration/commands/RenameField.java b/nitrite/src/main/java/org/dizitart/no2/migration/commands/RenameField.java
index 15631ce0a..2c8a6bbd4 100644
--- a/nitrite/src/main/java/org/dizitart/no2/migration/commands/RenameField.java
+++ b/nitrite/src/main/java/org/dizitart/no2/migration/commands/RenameField.java
@@ -5,7 +5,7 @@
import org.dizitart.no2.collection.Document;
import org.dizitart.no2.collection.NitriteId;
import org.dizitart.no2.common.tuples.Pair;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.store.IndexCatalog;
/**
@@ -21,7 +21,7 @@ public class RenameField extends BaseCommand implements Command {
public void execute(Nitrite nitrite) {
initialize(nitrite, collectionName);
- boolean indexExists = indexCatalog.hasIndexEntry(collectionName, oldName);
+ boolean indexExists = indexCatalog.hasIndexDescriptor(collectionName, oldName);
for (Pair entry : nitriteMap.entries()) {
Document document = entry.getSecond();
if (document.containsKey(oldName)) {
@@ -35,8 +35,8 @@ public void execute(Nitrite nitrite) {
if (indexExists) {
IndexCatalog indexCatalog = nitrite.getStore().getIndexCatalog();
- IndexEntry indexEntry = indexCatalog.findIndexEntry(collectionName, oldName);
- String indexType = indexEntry.getIndexType();
+ IndexDescriptor indexDescriptor = indexCatalog.findIndexDescriptor(collectionName, oldName);
+ String indexType = indexDescriptor.getIndexType();
operations.dropIndex(oldName);
operations.createIndex(newName, indexType, false);
diff --git a/nitrite/src/main/java/org/dizitart/no2/module/PluginManager.java b/nitrite/src/main/java/org/dizitart/no2/module/PluginManager.java
index d041e7ef8..ffb7f011b 100644
--- a/nitrite/src/main/java/org/dizitart/no2/module/PluginManager.java
+++ b/nitrite/src/main/java/org/dizitart/no2/module/PluginManager.java
@@ -36,7 +36,7 @@
@Slf4j
@Getter
public class PluginManager {
- private final Map indexerMap;
+ private final Map indexerMap;
private NitriteMapper nitriteMapper;
private NitriteStore> nitriteStore;
private final NitriteConfig nitriteConfig;
@@ -76,8 +76,8 @@ public void initializePlugins() {
}
if (!indexerMap.isEmpty()) {
- for (Indexer indexer : indexerMap.values()) {
- initializePlugin(indexer);
+ for (NitriteIndexer nitriteIndexer : indexerMap.values()) {
+ initializePlugin(nitriteIndexer);
}
}
}
@@ -117,13 +117,13 @@ private void loadIfNitriteMapper(NitritePlugin plugin) {
}
private synchronized void loadIfIndexer(NitritePlugin plugin) {
- if (plugin instanceof Indexer) {
- Indexer indexer = (Indexer) plugin;
- if (indexerMap.containsKey(indexer.getIndexType())) {
+ if (plugin instanceof NitriteIndexer) {
+ NitriteIndexer nitriteIndexer = (NitriteIndexer) plugin;
+ if (indexerMap.containsKey(nitriteIndexer.getIndexType())) {
throw new PluginException("multiple Indexer found for type "
- + indexer.getIndexType());
+ + nitriteIndexer.getIndexType());
}
- this.indexerMap.put(indexer.getIndexType(), indexer);
+ this.indexerMap.put(nitriteIndexer.getIndexType(), nitriteIndexer);
}
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/repository/DefaultObjectRepository.java b/nitrite/src/main/java/org/dizitart/no2/repository/DefaultObjectRepository.java
index 8d46de855..e8ae27347 100644
--- a/nitrite/src/main/java/org/dizitart/no2/repository/DefaultObjectRepository.java
+++ b/nitrite/src/main/java/org/dizitart/no2/repository/DefaultObjectRepository.java
@@ -21,9 +21,10 @@
import org.dizitart.no2.collection.NitriteCollection;
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.meta.Attributes;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.mapper.NitriteMapper;
import org.dizitart.no2.store.NitriteStore;
@@ -53,33 +54,33 @@ class DefaultObjectRepository implements ObjectRepository {
}
@Override
- public void createIndex(String field, IndexOptions indexOptions) {
- collection.createIndex(field, indexOptions);
+ public void createIndex(Fields fields, IndexOptions indexOptions) {
+ collection.createIndex(fields, indexOptions);
}
@Override
- public void rebuildIndex(String field, boolean isAsync) {
- collection.rebuildIndex(field, isAsync);
+ public void rebuildIndex(Fields fields, boolean isAsync) {
+ collection.rebuildIndex(fields, isAsync);
}
@Override
- public Collection listIndices() {
+ public Collection listIndices() {
return collection.listIndices();
}
@Override
- public boolean hasIndex(String field) {
- return collection.hasIndex(field);
+ public boolean hasIndex(Fields fields) {
+ return collection.hasIndex(fields);
}
@Override
- public boolean isIndexing(String field) {
- return collection.isIndexing(field);
+ public boolean isIndexing(Fields fields) {
+ return collection.isIndexing(fields);
}
@Override
- public void dropIndex(String field) {
- collection.dropIndex(field);
+ public void dropIndex(Fields fields) {
+ collection.dropIndex(fields);
}
@Override
diff --git a/nitrite/src/main/java/org/dizitart/no2/repository/ObjectRepository.java b/nitrite/src/main/java/org/dizitart/no2/repository/ObjectRepository.java
index cf8062468..ec6997f10 100644
--- a/nitrite/src/main/java/org/dizitart/no2/repository/ObjectRepository.java
+++ b/nitrite/src/main/java/org/dizitart/no2/repository/ObjectRepository.java
@@ -46,29 +46,25 @@
*
* An object repository is observable like its underlying {@link NitriteCollection}.
*
- * [[app-listing]]
- * [source,java]
- * .Create a repository
- * --
+ *
Create a repository
+ *
+ * {@code
* // create/open a database
* Nitrite db = Nitrite.builder()
- * .openOrCreate("user", "password");
- *
- * // create an object repository
- * ObjectRepository<Employee> employeeStore = db.getRepository(Employee.class);
- *
- * // observe any change to the repository
- * employeeStore.register(new ChangeListener() {
+ * .openOrCreate("user", "password");
*
- * @param the type of the object to store.
- * @author Anindya Chatterjee.
+ * // create an object repository
+ * ObjectRepository employeeStore = db.getRepository(Employee.class);
*
* // insert an object
* Employee emp = new Employee();
* emp.setName("John Doe");
* employeeStore.insert(emp);
- *
- * --
+ * }
+ *
+ *
+ * @param the type of the object to store.
+ * @author Anindya Chatterjee.
* @see EventAware
* @see Document
* @see NitriteId
@@ -88,16 +84,16 @@ public interface ObjectRepository extends PersistentCollection {
* If any of the value is already indexed in the repository, then after insertion the
* index will also be updated.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Insert}.
+ *
*
* @param object the object to insert
* @param others other objects to insert in a batch.
* @return the result of the write operation.
- * @throws ValidationException if `object` is `null`.
- * @throws InvalidIdException if the id value contains `null` value.
+ * @throws ValidationException if {@code object} is {@code null}.
+ * @throws InvalidIdException if the id value contains {@code null} value.
* @throws InvalidIdException if the id value contains non comparable type, i.e. type that does not implement {@link Comparable}.
* @throws InvalidIdException if the id contains value which is not of the same java type as of other objects' id in the collection.
* @throws UniqueConstraintException if the value of id value clashes with the id of another object in the collection.
@@ -124,26 +120,24 @@ default WriteResult insert(T object, T... others) {
/**
* Updates object in the repository. If the filter does not find
- * any object in the collection, then the `update` object will be inserted.
+ * any object in the collection, then the {@code update} object will be inserted.
*
- * If the `filter` is `null`, it will update all objects in the collection.
+ * If the {@code filter} is {@code null}, it will update all objects in the collection.
*
- * [icon="{@docRoot}/alert.png"]
- * [CAUTION]
- * ====
- * If the `update` object has a non `null` value in the id value, this value
+ * CAUTION:
+ * If the {@code update} object has a non {@code null} value in the id value, this value
* will be removed before update.
- * ====
+ *
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Update}.
+ *
*
* @param filter the filter to apply to select objects from the collection.
* @param update the modifications to apply.
* @return the result of the update operation.
- * @throws ValidationException if the `update` object is `null`.
+ * @throws ValidationException if the {@code update} object is {@code null}.
*/
default WriteResult update(Filter filter, T update) {
return update(filter, update, false);
@@ -151,95 +145,88 @@ default WriteResult update(Filter filter, T update) {
/**
* Updates object in the repository. Update operation can be customized
- * with the help of `updateOptions`.
+ * with the help of {@code updateOptions}.
*
- * If the `filter` is `null`, it will update all objects in the collection unless
- * `justOnce` is set to `true` in `updateOptions`.
+ * If the {@code filter} is {@code null}, it will update all objects in the collection unless
+ * {@code justOnce} is set to {@code true} in {@code updateOptions}.
*
- * [icon="{@docRoot}/alert.png"]
- * [CAUTION]
- * ====
- * If the `update` object has a non `null` value in the id value, this value
+ * CAUTION:
+ * If the {@code update} object has a non {@code null} value in the id value, this value
* will be removed before update.
- * ====
+ *
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
- * {@link EventType#Update} or
- * {@link EventType#Insert}.
+ * {@link EventType#Update} or {@link EventType#Insert}.
+ *
*
* @param filter the filter to apply to select objects from the collection.
* @param update the modifications to apply.
- * @param insertIfAbsent if set to `true`, `update` object will be inserted if not found.
+ * @param insertIfAbsent if set to {@code true}, {@code update} object will be inserted if not found.
* @return the result of the update operation.
- * @throws ValidationException if the `update` object is `null`.
- * @throws ValidationException if `updateOptions` is `null`.
+ * @throws ValidationException if the {@code update} object is {@code null}.
+ * @throws ValidationException if {@code updateOptions} is {@code null}.
*/
WriteResult update(Filter filter, T update, boolean insertIfAbsent);
/**
- * Updates object in the repository by setting the field specified in `document`.
+ * Updates object in the repository by setting the field specified in {@code document}.
*
- * If the `filter` is `null`, it will update all objects in the collection.
+ * If the {@code filter} is {@code null}, it will update all objects in the collection.
*
- * [icon="{@docRoot}/alert.png"]
- * [CAUTION]
- * ====
- * The `update` document should not contain `_id` field.
- * ====
+ * CAUTION:
+ * The {@code update} document should not contain {@code _id} field.
+ *
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Update}.
+ *
*
* @param filter the filter to apply to select objects from the collection.
* @param update the modifications to apply.
* @return the result of the update operation.
- * @throws ValidationException if the `update` object is `null`.
+ * @throws ValidationException if the {@code update} object is {@code null}.
*/
default WriteResult update(Filter filter, Document update) {
return update(filter, update, false);
}
/**
- * Updates object in the repository by setting the field specified in `document`.
+ * Updates object in the repository by setting the field specified in {@code document}.
* Update operation can either update the first matching object or all matching
- * objects depending on the value of `justOnce`.
+ * objects depending on the value of {@code justOnce}.
*
- * If the `filter` is `null`, it will update all objects in the collection unless
- * `justOnce` is set to `true`.
+ * If the {@code filter} is {@code null}, it will update all objects in the collection unless
+ * {@code justOnce} is set to {@code true}.
*
- * [icon="{@docRoot}/alert.png"]
- * [CAUTION]
- * ====
- * The `update` document should not contain `_id` field.
- * ====
+ * CAUTION:
+ * The {@code update} document should not contain {@code _id} field.
+ *
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Update}.
- *
+ *
+ *
* @param filter the filter to apply to select objects from the collection.
* @param update the modifications to apply.
* @param justOnce indicates if update should be applied on first matching object or all.
* @return the result of the update operation.
- * @throws ValidationException if the `update` object is `null`.
+ * @throws ValidationException if the {@code update} object is {@code null}.
*/
WriteResult update(Filter filter, Document update, boolean justOnce);
/**
* Removes matching elements from the collection.
*
- * If the `filter` is `null`, it will remove all objects from the collection.
+ * If the {@code filter} is {@code null}, it will remove all objects from the collection.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Remove}.
- *
+ *
+ *
* @param filter the filter to apply to select elements from collection.
* @return the result of the remove operation.
*/
@@ -249,16 +236,16 @@ default WriteResult remove(Filter filter) {
/**
* Removes object from the collection. Remove operation can be customized by
- * `removeOptions`.
+ * {@code removeOptions}.
*
- * If the `filter` is `null`, it will remove all objects in the collection unless
- * `justOnce` is set to `true` in `removeOptions`.
+ * If the {@code filter} is {@code null}, it will remove all objects in the collection unless
+ * {@code justOnce} is set to {@code true} in {@code removeOptions}.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: This operations will notify all {@link CollectionEventListener}
* instances registered to this collection with change type
* {@link EventType#Remove}.
- *
+ *
+ *
* @param filter the filter to apply to select objects from collection.
* @param justOne indicates if only one element will be removed or all of them.
* @return the result of the remove operation.
@@ -278,13 +265,13 @@ default WriteResult remove(Filter filter) {
*
* See {@link Filter} for all available filters.
*
- * [icon="{@docRoot}/note.png"]
* NOTE: If there is an index on the value specified in the filter, this operation
* will take advantage of the index.
+ *
*
* @param filter the filter to apply to select objects from collection.
* @return a cursor to all selected objects.
- * @throws ValidationException if `filter` is null.
+ * @throws ValidationException if {@code filter} is null.
* @see Filter
* @see Cursor#project(Class)
*/
@@ -292,14 +279,14 @@ default WriteResult remove(Filter filter) {
/**
* Gets a single element from the repository by its id. If no element
- * is found, it will return `null`. The object must have a field annotated with {@link Id},
+ * is found, it will return {@code null}. The object must have a field annotated with {@link Id},
* otherwise this call will throw {@link InvalidIdException}.
*
* @param the type parameter
* @param id the id value
* @return the unique object associated with the id.
- * @throws ValidationException if `id` is `null`.
- * @throws InvalidIdException if the id value is `null`, or the type is not compatible.
+ * @throws ValidationException if `id` is {@code null}.
+ * @throws InvalidIdException if the id value is {@code null}, or the type is not compatible.
* @throws NotIdentifiableException if the object has no field marked with {@link Id}.
*/
T getById(I id);
diff --git a/nitrite/src/main/java/org/dizitart/no2/store/IndexCatalog.java b/nitrite/src/main/java/org/dizitart/no2/store/IndexCatalog.java
index 24eae380b..fabea140d 100644
--- a/nitrite/src/main/java/org/dizitart/no2/store/IndexCatalog.java
+++ b/nitrite/src/main/java/org/dizitart/no2/store/IndexCatalog.java
@@ -16,7 +16,8 @@
package org.dizitart.no2.store;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.common.Fields;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexMeta;
import java.util.Collection;
@@ -39,88 +40,88 @@ public IndexCatalog(NitriteStore> nitriteStore) {
this.nitriteStore = nitriteStore;
}
- public boolean hasIndexEntry(String collectionName, String field) {
- NitriteMap indexMetaMap = getIndexMetaMap(collectionName);
- if (!indexMetaMap.containsKey(field)) return false;
+ public boolean hasIndexDescriptor(String collectionName, Fields fields) {
+ NitriteMap indexMetaMap = getIndexMetaMap(collectionName);
+ if (!indexMetaMap.containsKey(fields)) return false;
- IndexMeta indexMeta = indexMetaMap.get(field);
+ IndexMeta indexMeta = indexMetaMap.get(fields);
return indexMeta != null;
}
- public IndexEntry createIndexEntry(String collectionName, String field, String indexType) {
- IndexEntry index = new IndexEntry(indexType, field, collectionName);
+ public IndexDescriptor createIndexDescriptor(String collectionName, Fields fields, String indexType) {
+ IndexDescriptor index = new IndexDescriptor(indexType, fields, collectionName);
IndexMeta indexMeta = new IndexMeta();
- indexMeta.setIndexEntry(index);
+ indexMeta.setIndexDescriptor(index);
indexMeta.setIsDirty(new AtomicBoolean(false));
indexMeta.setIndexMap(getIndexMapName(index));
- getIndexMetaMap(collectionName).put(field, indexMeta);
+ getIndexMetaMap(collectionName).put(fields, indexMeta);
return index;
}
- public IndexEntry findIndexEntry(String collectionName, String field) {
- IndexMeta meta = getIndexMetaMap(collectionName).get(field);
+ public IndexDescriptor findIndexDescriptor(String collectionName, Fields fields) {
+ IndexMeta meta = getIndexMetaMap(collectionName).get(fields);
if (meta != null) {
- return meta.getIndexEntry();
+ return meta.getIndexDescriptor();
}
return null;
}
- public boolean isDirtyIndex(String collectionName, String field) {
- IndexMeta meta = getIndexMetaMap(collectionName).get(field);
+ public boolean isDirtyIndex(String collectionName, Fields fields) {
+ IndexMeta meta = getIndexMetaMap(collectionName).get(fields);
return meta != null && meta.getIsDirty().get();
}
- public Collection listIndexEntries(String collectionName) {
- Set indexSet = new LinkedHashSet<>();
+ public Collection listIndexDescriptors(String collectionName) {
+ Set indexSet = new LinkedHashSet<>();
for (IndexMeta indexMeta : getIndexMetaMap(collectionName).values()) {
- indexSet.add(indexMeta.getIndexEntry());
+ indexSet.add(indexMeta.getIndexDescriptor());
}
return Collections.unmodifiableSet(indexSet);
}
- public void dropIndexEntry(String collectionName, String field) {
- IndexMeta meta = getIndexMetaMap(collectionName).get(field);
- if (meta != null && meta.getIndexEntry() != null) {
+ public void dropIndexDescriptor(String collectionName, Fields fields) {
+ IndexMeta meta = getIndexMetaMap(collectionName).get(fields);
+ if (meta != null && meta.getIndexDescriptor() != null) {
String indexMapName = meta.getIndexMap();
nitriteStore.openMap(indexMapName, Object.class, Object.class).drop();
}
- getIndexMetaMap(collectionName).remove(field);
+ getIndexMetaMap(collectionName).remove(fields);
}
- public void beginIndexing(String collectionName, String field) {
- markDirty(collectionName, field, true);
+ public void beginIndexing(String collectionName, Fields fields) {
+ markDirty(collectionName, fields, true);
}
- public void endIndexing(String collectionName, String field) {
- markDirty(collectionName, field, false);
+ public void endIndexing(String collectionName, Fields fields) {
+ markDirty(collectionName, fields, false);
}
- private NitriteMap getIndexMetaMap(String collectionName) {
+ private NitriteMap getIndexMetaMap(String collectionName) {
String indexMetaName = getIndexMetaName(collectionName);
- return nitriteStore.openMap(indexMetaName, String.class, IndexMeta.class);
+ return nitriteStore.openMap(indexMetaName, Fields.class, IndexMeta.class);
}
private String getIndexMetaName(String collectionName) {
return INDEX_META_PREFIX + INTERNAL_NAME_SEPARATOR + collectionName;
}
- private String getIndexMapName(IndexEntry index) {
+ private void markDirty(String collectionName, Fields fields, boolean dirty) {
+ IndexMeta meta = getIndexMetaMap(collectionName).get(fields);
+ if (meta != null && meta.getIndexDescriptor() != null) {
+ meta.getIsDirty().set(dirty);
+ }
+ }
+
+ private String getIndexMapName(IndexDescriptor index) {
return INDEX_PREFIX +
INTERNAL_NAME_SEPARATOR +
index.getCollectionName() +
INTERNAL_NAME_SEPARATOR +
- index.getField() +
+ index.getFields().getEncodedName() +
INTERNAL_NAME_SEPARATOR +
index.getIndexType();
}
-
- private void markDirty(String collectionName, String field, boolean dirty) {
- IndexMeta meta = getIndexMetaMap(collectionName).get(field);
- if (meta != null && meta.getIndexEntry() != null) {
- meta.getIsDirty().set(dirty);
- }
- }
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/store/NitriteMap.java b/nitrite/src/main/java/org/dizitart/no2/store/NitriteMap.java
index 93956096f..d2117f7e6 100644
--- a/nitrite/src/main/java/org/dizitart/no2/store/NitriteMap.java
+++ b/nitrite/src/main/java/org/dizitart/no2/store/NitriteMap.java
@@ -127,6 +127,9 @@ public interface NitriteMap extends MetadataAware, AutoCloseable {
*/
RecordStream> entries();
+
+ RecordStream> reversedEntries();
+
/**
* Get the smallest key that is larger than the given key, or null if no
* such key exists.
diff --git a/nitrite/src/main/java/org/dizitart/no2/store/memory/InMemoryMap.java b/nitrite/src/main/java/org/dizitart/no2/store/memory/InMemoryMap.java
index ac1f5ce5f..92db60239 100644
--- a/nitrite/src/main/java/org/dizitart/no2/store/memory/InMemoryMap.java
+++ b/nitrite/src/main/java/org/dizitart/no2/store/memory/InMemoryMap.java
@@ -1,6 +1,6 @@
package org.dizitart.no2.store.memory;
-import org.dizitart.no2.common.NullEntry;
+import org.dizitart.no2.common.DBNull;
import org.dizitart.no2.common.RecordStream;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.common.util.Comparables;
@@ -19,7 +19,7 @@
*/
public class InMemoryMap implements NitriteMap {
private final NavigableMap backingMap;
- private final NavigableMap nullEntryMap;
+ private final NavigableMap nullEntryMap;
private final NitriteStore> nitriteStore;
private final String mapName;
@@ -35,7 +35,7 @@ public InMemoryMap(String mapName, NitriteStore> nitriteStore) {
@Override
public boolean containsKey(Key key) {
if (key == null) {
- return nullEntryMap.containsKey(NullEntry.getInstance());
+ return nullEntryMap.containsKey(DBNull.getInstance());
}
return backingMap.containsKey(key);
}
@@ -43,7 +43,7 @@ public boolean containsKey(Key key) {
@Override
public Value get(Key key) {
if (key == null) {
- return nullEntryMap.get(NullEntry.getInstance());
+ return nullEntryMap.get(DBNull.getInstance());
}
return backingMap.get(key);
}
@@ -74,7 +74,7 @@ public RecordStream values() {
public Value remove(Key key) {
Value value;
if (key == null) {
- value = nullEntryMap.remove(NullEntry.getInstance());
+ value = nullEntryMap.remove(DBNull.getInstance());
} else {
value = backingMap.remove(key);
}
@@ -86,7 +86,7 @@ public Value remove(Key key) {
public RecordStream keySet() {
return RecordStream.fromIterable(() -> new Iterator() {
final Iterator keyIterator = backingMap.keySet().iterator();
- final Iterator nullEntryIterator = nullEntryMap.keySet().iterator();
+ final Iterator nullEntryIterator = nullEntryMap.keySet().iterator();
@Override
public boolean hasNext() {
@@ -112,7 +112,7 @@ public Key next() {
public void put(Key key, Value value) {
notNull(value, "value cannot be null");
if (key == null) {
- nullEntryMap.put(NullEntry.getInstance(), value);
+ nullEntryMap.put(DBNull.getInstance(), value);
} else {
Map.Entry firstEntry = backingMap.firstEntry();
if (firstEntry != null) {
@@ -144,30 +144,12 @@ public Value putIfAbsent(Key key, Value value) {
@Override
public RecordStream> entries() {
- return RecordStream.fromIterable(() -> new Iterator>() {
- private final Iterator> entryIterator = backingMap.entrySet().iterator();
- private final Iterator> nullEntryIterator = nullEntryMap.entrySet().iterator();
-
- @Override
- public boolean hasNext() {
- boolean result = nullEntryIterator.hasNext();
- if (!result) {
- return entryIterator.hasNext();
- }
- return true;
- }
+ return getStream(backingMap, nullEntryMap);
+ }
- @Override
- public Pair next() {
- if (nullEntryIterator.hasNext()) {
- Map.Entry entry = nullEntryIterator.next();
- return new Pair<>(null, entry.getValue());
- } else {
- Map.Entry entry = entryIterator.next();
- return new Pair<>(entry.getKey(), entry.getValue());
- }
- }
- });
+ @Override
+ public RecordStream> reversedEntries() {
+ return getStream(backingMap.descendingMap(), nullEntryMap.descendingMap());
}
@Override
@@ -217,4 +199,34 @@ public void drop() {
public void close() {
}
+
+ private RecordStream> getStream(NavigableMap primaryMap,
+ NavigableMap nullEntryMap) {
+ return RecordStream.fromIterable(() -> new Iterator>() {
+ private final Iterator> entryIterator =
+ primaryMap.entrySet().iterator();
+ private final Iterator> nullEntryIterator =
+ nullEntryMap.entrySet().iterator();
+
+ @Override
+ public boolean hasNext() {
+ boolean result = nullEntryIterator.hasNext();
+ if (!result) {
+ return entryIterator.hasNext();
+ }
+ return true;
+ }
+
+ @Override
+ public Pair next() {
+ if (nullEntryIterator.hasNext()) {
+ Map.Entry entry = nullEntryIterator.next();
+ return new Pair<>(null, entry.getValue());
+ } else {
+ Map.Entry entry = entryIterator.next();
+ return new Pair<>(entry.getKey(), entry.getValue());
+ }
+ }
+ });
+ }
}
diff --git a/nitrite/src/main/java/org/dizitart/no2/transaction/DefaultTransactionalCollection.java b/nitrite/src/main/java/org/dizitart/no2/transaction/DefaultTransactionalCollection.java
index a9dc85a26..b6dd35517 100644
--- a/nitrite/src/main/java/org/dizitart/no2/transaction/DefaultTransactionalCollection.java
+++ b/nitrite/src/main/java/org/dizitart/no2/transaction/DefaultTransactionalCollection.java
@@ -1,5 +1,6 @@
package org.dizitart.no2.transaction;
+import lombok.Data;
import org.dizitart.no2.Nitrite;
import org.dizitart.no2.NitriteConfig;
import org.dizitart.no2.collection.*;
@@ -7,12 +8,13 @@
import org.dizitart.no2.collection.events.CollectionEventListener;
import org.dizitart.no2.collection.meta.Attributes;
import org.dizitart.no2.collection.operation.CollectionOperations;
+import org.dizitart.no2.common.Fields;
import org.dizitart.no2.common.WriteResult;
import org.dizitart.no2.common.event.EventBus;
import org.dizitart.no2.common.event.NitriteEventBus;
import org.dizitart.no2.exceptions.*;
import org.dizitart.no2.filters.Filter;
-import org.dizitart.no2.index.IndexEntry;
+import org.dizitart.no2.index.IndexDescriptor;
import org.dizitart.no2.index.IndexOptions;
import org.dizitart.no2.index.IndexType;
import org.dizitart.no2.store.NitriteMap;
@@ -34,6 +36,7 @@
/**
* @author Anindya Chatterjee
*/
+@Data
class DefaultTransactionalCollection implements NitriteCollection {
private final NitriteCollection primary;
private final TransactionContext transactionContext;
@@ -267,17 +270,17 @@ public String getName() {
}
@Override
- public void createIndex(String field, IndexOptions indexOptions) {
+ public void createIndex(Fields fields, IndexOptions indexOptions) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
// by default async is false while creating index
try {
writeLock.lock();
if (indexOptions == null) {
- collectionOperations.createIndex(field, IndexType.Unique, false);
+ collectionOperations.createIndex(fields, IndexType.Unique, false);
} else {
- collectionOperations.createIndex(field, indexOptions.getIndexType(),
+ collectionOperations.createIndex(fields, indexOptions.getIndexType(),
indexOptions.isAsync());
}
} finally {
@@ -286,46 +289,46 @@ public void createIndex(String field, IndexOptions indexOptions) {
JournalEntry journalEntry = new JournalEntry();
journalEntry.setChangeType(ChangeType.CreateIndex);
- journalEntry.setCommit(() -> primary.createIndex(field, indexOptions));
- journalEntry.setRollback(() -> primary.dropIndex(field));
+ journalEntry.setCommit(() -> primary.createIndex(fields, indexOptions));
+ journalEntry.setRollback(() -> primary.dropIndex(fields));
transactionContext.getJournal().add(journalEntry);
}
@Override
- public void rebuildIndex(String field, boolean isAsync) {
+ public void rebuildIndex(Fields fields, boolean isAsync) {
checkOpened();
- notNull(field, "field cannot be null");
+ notNull(fields, "fields cannot be null");
- IndexEntry indexEntry;
+ IndexDescriptor indexDescriptor;
try {
readLock.lock();
- indexEntry = collectionOperations.findIndex(field);
+ indexDescriptor = collectionOperations.findIndex(fields);
} finally {
readLock.unlock();
}
- if (indexEntry != null) {
- validateRebuildIndex(indexEntry);
+ if (indexDescriptor != null) {
+ validateRebuildIndex(indexDescriptor);
try {
writeLock.lock();
- collectionOperations.rebuildIndex(indexEntry, isAsync);
+ collectionOperations.rebuildIndex(indexDescriptor, isAsync);
} finally {
writeLock.unlock();
}
} else {
- throw new IndexingException(field + " is not indexed");
+ throw new IndexingException(fields + " is not indexed");
}
JournalEntry journalEntry = new JournalEntry();
journalEntry.setChangeType(ChangeType.RebuildIndex);
- journalEntry.setCommit(() -> primary.rebuildIndex(field, isAsync));
- journalEntry.setRollback(() -> primary.rebuildIndex(field, isAsync));
+ journalEntry.setCommit(() -> primary.rebuildIndex(fields, isAsync));
+ journalEntry.setRollback(() -> primary.rebuildIndex(fields, isAsync));
transactionContext.getJournal().add(journalEntry);
}
@Override
- public Collection listIndices() {
+ public Collection