Przeglądaj źródła

resolve #75: new IQueryMap#update(index)

Ranides Atterwim 3 lat temu
rodzic
commit
8b491560de

+ 9 - 1
assira.commons/src/main/java/net/ranides/assira/index/IQueryMap.java

@@ -89,7 +89,15 @@ public interface IQueryMap<V> {
      */
      */
     void updateAll();
     void updateAll();
 
 
-    // @todo #75 update(index)
+    /**
+     * Triggers rebuilding only specified index.
+     * It is very costly operation, but less than rebuilding all indexes using {@link #updateAll()}.
+     * If you modified a lot of records, but you know that changes will affect only some indexes,
+     * you can update only them.
+     *
+     * @param index index
+     */
+    void updateAll(String index);
 
 
     /**
     /**
      * Removes specified record from container, updates all indexes.
      * Removes specified record from container, updates all indexes.

+ 22 - 0
assira.commons/src/main/java/net/ranides/assira/index/IQueryMapTree.java

@@ -117,6 +117,28 @@ public class IQueryMapTree<V> extends IQueryMapAbstract<V> {
             }
             }
         }
         }
     }
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void updateAll(String index) {
+        List<V> items = new ArrayList<>(values());
+
+        Comparator sortKey = sortIndexer.get(index);
+        if(sortKey != null) {
+            RBTreeMultiSet<V> sortIndex = sortValues.get(sortKey);
+            sortIndex.clear();
+            sortIndex.addAll(items);
+        }
+
+        Function mapKey = mapIndexer.get(index);
+        if(mapKey != null) {
+            RBTreeMultiMap<Object, V> mapIndex = mapValues.get(mapKey);
+            mapIndex.clear();
+            for(V item : items) {
+                mapIndex.put(mapKey.apply(item), item);
+            }
+        }
+    }
     
     
     @Override
     @Override
     public IQuery<V> find() {
     public IQuery<V> find() {

+ 70 - 14
assira.commons/src/test/java/net/ranides/assira/index/IndexTreeMapTest.java

@@ -6,17 +6,22 @@
  */
  */
 package net.ranides.assira.index;
 package net.ranides.assira.index;
 
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.Objects;
+
+import net.ranides.assira.collection.sets.RBTreeMultiSet;
 import net.ranides.assira.generic.CompareUtils;
 import net.ranides.assira.generic.CompareUtils;
 import org.junit.Test;
 import org.junit.Test;
 
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 
 
 /**
 /**
  *
  *
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
  */
-public class IndexTreeMapTest {
+public class IQueryMapTreeTest {
 
 
     @Test
     @Test
     public void testSetIndex() {
     public void testSetIndex() {
@@ -64,6 +69,45 @@ public class IndexTreeMapTest {
         );
         );
     }
     }
 
 
+    @Test
+    public void testReindex() {
+        IQueryMap<Person> db = new IQueryMapTree<>();
+
+        db.index("name", a -> a.name);
+        db.index("surname", (a,b) -> CompareUtils.cmp(a.surname, b.surname));
+        List<Person> data = putData(db);
+
+        assertQueryEquals("[{Helene C 19}, {Helene C 23}]", db.find().eq("name", "Helene"));
+        assertQueryEquals("[{Joe A 20}, {Peter A 17}, {Tom A 17}]", db.find().eq("surname", new Person("", "A", 0)));
+
+//      0  new Person("Tom", "A", 17)
+//      1  new Person("Tom", "B", 23)
+//      2  new Person("Joe", "A", 20)
+//      3  new Person("Helene", "C", 19)
+//      4  new Person("Andrew", "S", 23)
+//      5  new Person("Helene", "C", 23)
+//      6  new Person("George", "T", 17)
+//      7  new Person("Peter", "A", 17)
+
+        data.get(4).name = "Helene"; // new Person("Andrew", "S", 23)
+        data.get(5).name = "Catherine"; // new Person("Helene", "C", 23);
+
+        data.get(0).surname = "X"; // new Person("Tom", "A", 17)
+        data.get(6).surname = "A"; // new Person("George", "T", 17)
+        data.get(7).surname = "X"; // new Person("Peter", "A", 17)
+
+        // a bit broken indexes
+        assertQueryNotEquals("[{Helene C 19}, {Helene S 23}]", db.find().eq("name", "Helene"));
+        assertQueryNotEquals("[{George A 17}, {Joe A 20}]", db.find().eq("surname", new Person("", "A", 0)));
+
+        // fixed indexes
+        db.updateAll("name");
+        db.updateAll("surname");
+
+        assertQueryEquals("[{Helene C 19}, {Helene S 23}]", db.find().eq("name", "Helene"));
+        assertQueryEquals("[{George A 17}, {Joe A 20}]", db.find().eq("surname", new Person("", "A", 0)));
+    }
+
     @Test
     @Test
     public void testMapIndex() {
     public void testMapIndex() {
         
         
@@ -143,22 +187,34 @@ public class IndexTreeMapTest {
         assertEquals(expected, query.sort().list().toString());
         assertEquals(expected, query.sort().list().toString());
     }
     }
 
 
-    private static void putData(IQueryMap<Person> db) {
-        db.put(new Person("Tom", "A", 17));
-        db.put(new Person("Tom", "B", 23));
-        db.put(new Person("Joe", "A", 20));
-        db.put(new Person("Helene", "C", 19));
-        db.put(new Person("Andrew", "S", 23));
-        db.put(new Person("Helene", "C", 23));
-        db.put(new Person("George", "T", 17));
-        db.put(new Person("Peter", "A", 17));
+    private static void assertQueryNotEquals(String expected, IQuery<Person> query) {
+        assertNotEquals(expected, query.sort().list().toString());
     }
     }
-    
+
+    private static List<Person> putData(IQueryMap<Person> db) {
+        List<Person> records = Arrays.asList(
+            new Person("Tom", "A", 17),
+            new Person("Tom", "B", 23),
+            new Person("Joe", "A", 20),
+            new Person("Helene", "C", 19),
+            new Person("Andrew", "S", 23),
+            new Person("Helene", "C", 23),
+            new Person("George", "T", 17),
+            new Person("Peter", "A", 17)
+        );
+
+        for(Person person : records) {
+            db.put(person);
+        }
+
+        return records;
+    }
+
     private static final class Person implements Comparable<Person> {
     private static final class Person implements Comparable<Person> {
         
         
-        public final String name;
-        public final String surname;
-        public final int age;
+        public String name;
+        public String surname;
+        public int age;
 
 
         public Person(String name, String surname, int age) {
         public Person(String name, String surname, int age) {
             this.name = name;
             this.name = name;