check for dirty indexes before add it to a collection
New feature/Constraint: When a collection with indexes is filled with data, you can have that indexes into separate variables or static fields. Then you could add this indexes to a new collection (p.ex the same collection but re-instantiated from a persistence serialization system), but this indexes can have data and can associate with the new collection silent and dirty. This checks that the index was used and is dirty and throws an exception to warn the user.
If you let this with the QueryOption you assume that you could have indexes with different data on multiple collections, or data into the index that could be changed into the collection after a de-serialization process
Added new QueryOption DISABLE_DIRTY_CHECK_OPTION boolean that handles the deactivation of the newfeature/constraint. This check is disabled by default.
`public class Main { private SimpleAttribute<HotelRate, Long> codAttribute = attribute(HotelRate::getCod); private Attribute<HotelRate, String> nameAttribute = attribute(HotelRate::getName); private Attribute<HotelRate, String> desAttribute = attribute(HotelRate::getDes); private Index<HotelRate> uniqueIndex = HashIndex.onAttribute(codAttribute); private Index<HotelRate> nameIndex = HashIndex.onAttribute(nameAttribute); private Index<HotelRate> desIndex = HashIndex.onAttribute(desAttribute);
private HotelRate hotelRate1 = HotelRate.builder().cod(1L).name("myName").cur(null).des("des").otherName("other").build();
private HotelRate hotelRate2 = HotelRate.builder().cod(1L).name("myName2").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate3 = HotelRate.builder().cod(2L).name("myName2").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate4 = HotelRate.builder().cod(3L).name("myName3").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate5 = HotelRate.builder().cod(4L).name("myName3").cur("cur2").des("des1").otherName("other1").build();
public static void main(String[] args) {
new Main().run();
}
public void run() {
IndexedCollection<HotelRate> indexedCollection = new ConcurrentIndexedCollection<>(OnHeapPersistence.onPrimaryKey(codAttribute));
indexedCollection.addIndex(uniqueIndex);
indexedCollection.addIndex(nameIndex);
indexedCollection.addIndex(desIndex);
indexedCollection.add(hotelRate1);
indexedCollection.add(hotelRate3);
indexedCollection.add(hotelRate4);
indexedCollection.add(hotelRate5);
String outputCodWithoutIndexSearch = indexedCollection.stream().filter(h -> h.getCod().equals(1L)).findFirst().get().toString();
Assert.assertEquals(outputCodWithoutIndexSearch,"HotelRate(cod=1, name=myName, cur=null, des=des, otherName=other)");
String outputMyName = indexedCollection.retrieve(equal(nameAttribute,"myName")).uniqueResult().toString();
Assert.assertEquals(outputMyName,"HotelRate(cod=1, name=myName, cur=null, des=des, otherName=other)");
indexedCollection = new ConcurrentIndexedCollection<>(OnHeapPersistence.onPrimaryKey(codAttribute));
indexedCollection.addIndex(uniqueIndex);
indexedCollection.addIndex(nameIndex);
indexedCollection.addIndex(desIndex);
indexedCollection.add(hotelRate2);
indexedCollection.add(hotelRate3);
indexedCollection.add(hotelRate4);
indexedCollection.add(hotelRate5);
String outputCodWithoutIndexSearchAfterRecreate = indexedCollection.stream().filter(h -> h.getCod().equals(1L)).findFirst().get().toString();
Assert.assertEquals(outputCodWithoutIndexSearchAfterRecreate,"HotelRate(cod=1, name=myName2, cur=cur1, des=des1, otherName=other1)");
String outputMyNameAfterRecreate = indexedCollection.retrieve(equal(nameAttribute,"myName")).uniqueResult().toString();
Assert.assertEquals(outputMyNameAfterRecreate,"HotelRate(cod=1, name=myName2, cur=cur1, des=des1, otherName=other1)");
}
}`
The output: Exception in thread "main" org.junit.ComparisonFailure: expected:<...e(cod=1, name=myName[, cur=null, des=des, otherName=other])> but was:<...e(cod=1, name=myName[2, cur=cur1, des=des1, otherName=other1])> at org.junit.Assert.assertEquals(Assert.java:115) at org.junit.Assert.assertEquals(Assert.java:144) at es.nangel.cqengine.Main.run(Main.java:69) at es.nangel.cqengine.Main.main(Main.java:35)
`public class Main { private SimpleAttribute<HotelRate, Long> codAttribute = attribute(HotelRate::getCod); private Attribute<HotelRate, String> nameAttribute = attribute(HotelRate::getName); private Attribute<HotelRate, String> desAttribute = attribute(HotelRate::getDes); private Index<HotelRate> uniqueIndex = UniqueIndex.onAttribute(codAttribute); private Index<HotelRate> nameIndex = HashIndex.onAttribute(nameAttribute); private Index<HotelRate> desIndex = HashIndex.onAttribute(desAttribute);
private HotelRate hotelRate1 = HotelRate.builder().cod(1L).name("myName").cur(null).des("des").otherName("other").build();
private HotelRate hotelRate2 = HotelRate.builder().cod(1L).name("myName2").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate3 = HotelRate.builder().cod(2L).name("myName2").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate4 = HotelRate.builder().cod(3L).name("myName3").cur("cur1").des("des1").otherName("other1").build();
private HotelRate hotelRate5 = HotelRate.builder().cod(4L).name("myName3").cur("cur2").des("des1").otherName("other1").build();
public static void main(String[] args) {
new Main().run();
}
public void run() {
IndexedCollection<HotelRate> indexedCollection = new ConcurrentIndexedCollection<>(OnHeapPersistence.onPrimaryKey(codAttribute));
indexedCollection.addIndex(uniqueIndex);
indexedCollection.addIndex(nameIndex);
indexedCollection.addIndex(desIndex);
indexedCollection.add(hotelRate1);
indexedCollection.add(hotelRate3);
indexedCollection.add(hotelRate4);
indexedCollection.add(hotelRate5);
String outputCodWithoutIndexSearch = indexedCollection.stream().filter(h -> h.getCod().equals(1L)).findFirst().get().toString();
Assert.assertEquals(outputCodWithoutIndexSearch,"HotelRate(cod=1, name=myName, cur=null, des=des, otherName=other)");
String outputMyName = indexedCollection.retrieve(equal(nameAttribute,"myName")).uniqueResult().toString();
Assert.assertEquals(outputMyName,"HotelRate(cod=1, name=myName, cur=null, des=des, otherName=other)");
indexedCollection = new ConcurrentIndexedCollection<>(OnHeapPersistence.onPrimaryKey(codAttribute));
indexedCollection.addIndex(uniqueIndex);
indexedCollection.addIndex(nameIndex);
indexedCollection.addIndex(desIndex);
indexedCollection.add(hotelRate2);
indexedCollection.add(hotelRate3);
indexedCollection.add(hotelRate4);
indexedCollection.add(hotelRate5);
String outputCodWithoutIndexSearchAfterRecreate = indexedCollection.stream().filter(h -> h.getCod().equals(1L)).findFirst().get().toString();
Assert.assertEquals(outputCodWithoutIndexSearchAfterRecreate,"HotelRate(cod=1, name=myName2, cur=cur1, des=des1, otherName=other1)");
String outputMyNameAfterRecreate = indexedCollection.retrieve(equal(nameAttribute,"myName")).uniqueResult().toString();
Assert.assertEquals(outputMyNameAfterRecreate,"HotelRate(cod=1, name=myName2, cur=cur1, des=des1, otherName=other1)");
}
}`
The output: Exception in thread "main" com.googlecode.cqengine.index.unique.UniqueIndex$UniqueConstraintViolatedException: The application has attempted to add a duplicate object to the UniqueIndex on attribute 'es.nangel.cqengine.Main$$Lambda$1/2094548358', potentially causing inconsistencies between indexes. UniqueIndex should not be used with attributes which do not uniquely identify objects. Problematic attribute value: '1', problematic duplicate object: HotelRate(cod=1, name=myName2, cur=cur1, des=des1, otherName=other1) at com.googlecode.cqengine.index.unique.UniqueIndex.addAll(UniqueIndex.java:244) at com.googlecode.cqengine.engine.CollectionQueryEngine$12.perform(CollectionQueryEngine.java:1125) at com.googlecode.cqengine.engine.CollectionQueryEngine.forEachIndexDo(CollectionQueryEngine.java:1206) at com.googlecode.cqengine.engine.CollectionQueryEngine.addAll(CollectionQueryEngine.java:1122) at com.googlecode.cqengine.ConcurrentIndexedCollection.add(ConcurrentIndexedCollection.java:351) at es.nangel.cqengine.Main.run(Main.java:61) at es.nangel.cqengine.Main.main(Main.java:35)
Process finished with exit code 1