Ranides Atterwim 5 سال پیش
والد
کامیت
97bb183b15

+ 4 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/CQuery.java

@@ -6,6 +6,8 @@
  */
 package net.ranides.assira.collection.query;
 
+import java.io.IOException;
+import java.nio.file.Path;
 import java.util.*;
 import java.util.function.*;
 import java.util.stream.Collector;
@@ -62,6 +64,8 @@ public interface CQuery<T> extends Iterable<T> {
 
     CQuery<T> fetch();
 
+    CQuery<T> cache(Path filename) throws IOException;
+
     CQuery<T> append(CQuery<T> next);
 
     <K> Map<K,T> group(Function<? super T, ? extends K> key);

+ 17 - 0
assira.core/src/main/java/net/ranides/assira/collection/query/CQueryAbstract.java

@@ -6,6 +6,9 @@
  */
 package net.ranides.assira.collection.query;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.*;
 import java.util.function.*;
 import java.util.stream.Collector;
@@ -27,6 +30,8 @@ import net.ranides.assira.functional.checked.CheckedFunction;
 import net.ranides.assira.functional.checked.CheckedSupplier;
 import net.ranides.assira.functional.special.Fold;
 import net.ranides.assira.generic.CompareUtils;
+import net.ranides.assira.generic.SerializationUtils;
+import net.ranides.assira.generic.TypeToken;
 import net.ranides.assira.reflection.*;
 
 /**
@@ -70,6 +75,18 @@ public abstract class CQueryAbstract<T> implements CQuery<T> {
         return CQuery.from().collection(list());
     }
 
+    @Override
+    public CQuery<T> cache(Path filename) throws IOException {
+        List<T> data;
+        if(Files.exists(filename)) {
+            data = SerializationUtils.read(new TypeToken<List<T>>() {}, filename);
+        } else {
+            data = list();
+            SerializationUtils.write(filename, data);
+        }
+        return CQuery.from().collection(data);
+    }
+
     @Override
     public CQuery<T> limit(Predicate<? super T> p) {
         return new CQIterable<>(() -> IteratorUtils.limit(iterator(), p));

+ 37 - 6
assira.core/src/main/java/net/ranides/assira/generic/SerializationUtils.java

@@ -8,10 +8,14 @@ package net.ranides.assira.generic;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Iterator;
 
@@ -50,21 +54,48 @@ public final class SerializationUtils {
         }
     }
 
+    public static void write(Path target, Object value) throws IOException {
+        try (FileOutputStream fos = new FileOutputStream(target.toFile()) ){
+            try (ObjectOutputStream ostream = new ObjectOutputStream(fos)) {
+                ostream.writeObject(value);
+                ostream.flush();
+            }
+        }
+    }
+
     public static <T> T read(Class<T> type, byte[] data) throws IOException {
         return type.cast(read(data));
     }
 
+    public static <T> T read(Class<T> type, Path input) throws IOException {
+        return type.cast(read(input));
+    }
+
     public static <T> T read(IClass<T> type, byte[] data) throws IOException {
         return type.cast(read(data));
     }
 
+    public static <T> T read(IClass<T> type, Path input) throws IOException {
+        return type.cast(read(input));
+    }
+
     public static Object read(byte[] data) throws IOException {
-        try {
-            ByteArrayInputStream ibs = new ByteArrayInputStream(data);
-            ObjectInputStream istream = new ObjectInputStream(ibs);
-            return istream.readObject();
-        } catch(ClassNotFoundException cause) {
-            throw new IOException(cause);
+        try (ByteArrayInputStream ibs = new ByteArrayInputStream(data)) {
+            try(ObjectInputStream istream = new ObjectInputStream(ibs)) {
+                return istream.readObject();
+            } catch(ClassNotFoundException cause) {
+                throw new IOException(cause);
+            }
+        }
+    }
+
+    public static Object read(Path input) throws IOException {
+        try (FileInputStream ifs = new FileInputStream(input.toFile())) {
+            try(ObjectInputStream istream = new ObjectInputStream(ifs)) {
+                return istream.readObject();
+            } catch(ClassNotFoundException cause) {
+                throw new IOException(cause);
+            }
         }
     }
     

+ 55 - 1
assira.core/src/test/java/net/ranides/assira/collection/query/CQueryTest.java

@@ -6,9 +6,16 @@
  */
 package net.ranides.assira.collection.query;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
 
 import org.junit.Test;
 import static net.ranides.assira.junit.NewAssert.*;
@@ -53,5 +60,52 @@ public class CQueryTest {
         assertEquals(exp2, query.list());
         assertEquals(exp2, query.list());
     }
-    
+
+    @Test
+    public void testCache() throws IOException {
+        Path temp = File.createTempFile("cquery", ".bin").toPath();
+        Files.deleteIfExists(temp);
+
+        List<String> events = new ArrayList<>();
+
+        Supplier<Stream<Integer>> creator = () -> {
+            events.add("create");
+            return Arrays.stream(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
+        };
+
+        Predicate<Integer> filter1 = v -> {
+            events.add("A"+v);
+            return v % 2 == 0;
+        };
+        Predicate<Integer> filter2 = v -> {
+            events.add("B"+v);
+            return v < 6;
+        };
+
+        CQuery<Integer> query = CQuery.from(creator::get)
+            .filter(filter1)
+            .cache(temp)
+            .filter(filter2);
+
+        List<Integer> data1 = query.list();
+        List<Integer> data2 = query.list();
+        List<Integer> data3 = query.list();
+        List<Integer> data4 = query.list();
+
+        assertEquals(data1, data2);
+        assertEquals(data1, data3);
+        assertEquals(data1, data4);
+
+        List<String> expected = Arrays.asList(
+            "create",
+            "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10",
+            "B2", "B4", "B6", "B8", "B10",
+            "B2", "B4", "B6", "B8", "B10",
+            "B2", "B4", "B6", "B8", "B10",
+            "B2", "B4", "B6", "B8", "B10"
+        );
+        assertEquals(expected, events);
+
+
+    }
 }