diff --git a/projects/annnvl/.gitignore b/projects/annnvl/.gitignore
new file mode 100644
index 0000000..5746aab
--- /dev/null
+++ b/projects/annnvl/.gitignore
@@ -0,0 +1 @@
+twitter4j.properties
diff --git a/projects/annnvl/pom.xml b/projects/annnvl/pom.xml
new file mode 100644
index 0000000..2ca0a92
--- /dev/null
+++ b/projects/annnvl/pom.xml
@@ -0,0 +1,59 @@
+
+
+ 4.0.0
+
+ ru.mipt.diht.students
+ parent
+ 1.0-SNAPSHOT
+
+ ru.mipt.diht.students
+ annnvl
+ 1.0-SNAPSHOT
+ annnvl
+ http://maven.apache.org
+
+ UTF-8
+
+
+
+ junit
+ junit
+ 4.8.2
+ test
+
+
+ org.twitter4j
+ twitter4j-stream
+ 4.0.4
+
+
+ org.mockito
+ mockito-core
+ 1.10.19
+ test
+
+
+
+ org.hamcrest
+ hamcrest-junit
+ 2.0.0.0
+
+
+
+ com.google.code.geocoder-java
+ geocoder-java
+ 0.16
+
+
+ com.google.maps
+ google-maps-services
+ 0.1.7
+
+
+ com.beust
+ jcommander
+ 1.48
+
+
+
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Aggregates.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Aggregates.java
new file mode 100644
index 0000000..7ea8271
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Aggregates.java
@@ -0,0 +1,60 @@
+package ru.mipt.diht.students.annnvl.CQL;
+/**
+ * Aggregate functions.
+ */
+import java.util.function.Function;
+import ru.mipt.diht.students.annnvl.CQL.impl.Avg;
+import ru.mipt.diht.students.annnvl.CQL.impl.Count;
+import ru.mipt.diht.students.annnvl.CQL.impl.Max;
+import ru.mipt.diht.students.annnvl.CQL.impl.Min;
+
+public class Aggregates {
+
+ /**
+ * Maximum value for expression for elements of given collecdtion.
+ *
+ * @param expression
+ * @param
+ * @param
+ * @return
+ */
+ public static > Function max(Function expression) {
+ return new Max<>(expression);
+ }
+
+ /**
+ * Minimum value for expression for elements of given collecdtion.
+ *
+ * @param expression
+ * @param
+ * @param
+ * @return
+ */
+ public static > Function min(Function expression) {
+ return new Min<>(expression);
+ }
+
+ /**
+ * Number of items in source collection that turns this expression into not null.
+ *
+ * @param expression
+ * @param
+ * @return
+ */
+ public static Function count(Function expression) {
+ return new Count<>(expression);
+ }
+
+
+ /**
+ * Average value for expression for elements of given collection.
+ *
+ * @param expression
+ * @param
+ * @return
+ */
+ public static Function avg(Function expression) {
+ return new Avg<>(expression);
+ }
+
+}
\ No newline at end of file
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/CollectionQuery.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/CollectionQuery.java
new file mode 100644
index 0000000..8e4d161
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/CollectionQuery.java
@@ -0,0 +1,107 @@
+package ru.mipt.diht.students.annnvl.CQL;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+
+import static ru.mipt.diht.students.annnvl.CQL.Aggregates.avg;
+import static ru.mipt.diht.students.annnvl.CQL.Aggregates.count;
+import static ru.mipt.diht.students.annnvl.CQL.CollectionQuery.Student.student;
+import static ru.mipt.diht.students.annnvl.CQL.Conditions.rlike;
+import static ru.mipt.diht.students.annnvl.CQL.OrderByConditions.asc;
+import static ru.mipt.diht.students.annnvl.CQL.OrderByConditions.desc;
+import static ru.mipt.diht.students.annnvl.CQL.Sources.list;
+import static ru.mipt.diht.students.annnvl.CQL.impl.FromStmt.from;
+
+public class CollectionQuery {
+
+ public static void main(String[] args) {
+ Iterable statistics =
+ from(list(
+ student("ivanov", LocalDate.parse("1986-08-06"), "494"),
+ student("ivanov", LocalDate.parse("1986-08-06"), "494")))
+ .select(Statistics.class, Student::getGroup, count(Student::getGroup), avg(Student::age))
+ .where(rlike(Student::getName, ".*ov").and(s -> s.age() > 20))
+ .groupBy(Student::getGroup)
+ .having(s -> s.getCount() > 0)
+ .orderBy(asc(Student::getGroup), desc(count(Student::getGroup)))
+ .limit(100)
+ .union()
+ .from(list(student("ivanov", LocalDate.parse("1985-08-06"), "494")))
+ .selectDistinct(Statistics.class, s -> "all", count(s -> 1), avg(Student::age))
+ .execute();
+ System.out.println(statistics);
+ }
+
+
+ public static class Student {
+ private final String name;
+
+ private final LocalDate dateOfBith;
+
+ private final String group;
+
+ public String getName() {
+ return name;
+ }
+
+ public Student(String name, LocalDate dateOfBith, String group) {
+ this.name = name;
+ this.dateOfBith = dateOfBith;
+ this.group = group;
+ }
+
+ public LocalDate getDateOfBith() {
+ return dateOfBith;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public long age() {
+ return ChronoUnit.YEARS.between(getDateOfBith(), LocalDateTime.now());
+ }
+
+ public static Student student(String name, LocalDate dateOfBith, String group) {
+ return new Student(name, dateOfBith, group);
+ }
+ }
+
+
+ public static class Statistics {
+
+ private final String group;
+ private final Long count;
+ private final Long age;
+
+ public String getGroup() {
+ return group;
+ }
+
+ public Long getCount() {
+ return count;
+ }
+
+
+ public Long getAge() {
+ return age;
+ }
+
+ public Statistics(String group, Long count, Long age) {
+ this.group = group;
+ this.count = count;
+ this.age = age;
+ }
+
+ @Override
+ public String toString() {
+ return "Statistics{"
+ + "group='" + group + '\''
+ + ", count=" + count
+ + ", age=" + age
+ + '}';
+ }
+ }
+
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Conditions.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Conditions.java
new file mode 100644
index 0000000..5ed9e17
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Conditions.java
@@ -0,0 +1,37 @@
+package ru.mipt.diht.students.annnvl.CQL;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Where clause conditions.
+ */
+public class Conditions {
+
+ /**
+ * Matches string result of expression against regexp pattern.
+ *
+ * @param expression expression result to match
+ * @param regexp pattern to match to
+ * @param source object type
+ * @return
+ */
+ public static Predicate rlike(Function expression, String regexp) {
+ return element -> expression.apply(element).matches(regexp);
+ }
+
+ /**
+ * Matches string result of expression against SQL like pattern.
+ *
+ * @param expression expression result to match
+ * @param pattern pattern to match to
+ * @param source object type
+ * @return
+ */
+ public static Predicate like(Function expression, String pattern) {
+ String newpattern = pattern.toLowerCase();
+ newpattern = newpattern.replace(".", "\\.").replace("?", ".").replace("%", ".*");
+ return rlike(expression, newpattern);
+ }
+
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/OrderByConditions.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/OrderByConditions.java
new file mode 100644
index 0000000..a9772d4
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/OrderByConditions.java
@@ -0,0 +1,37 @@
+package ru.mipt.diht.students.annnvl.CQL;
+
+import java.util.Comparator;
+import java.util.function.Function;
+
+/**
+ * OrderBy sort order helper methods.
+ */
+public class OrderByConditions {
+
+ /**
+ * Ascending comparator.
+ *
+ * @param expression
+ * @param
+ * @param
+ * @return
+ */
+ public static > Comparator asc(Function expression) {
+ return (o1, o2) -> expression.apply(o1).compareTo(expression.apply(o2));
+ }
+
+ /**
+ * Descending comparator.
+ *
+ * @param expression
+ * @param
+ * @param
+ * @return
+ */
+ public static > Comparator desc(Function expression) {
+ return (o1, o2) -> expression.apply(o2).compareTo(expression.apply(o1));
+ }
+
+}
+
+
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Sources.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Sources.java
new file mode 100644
index 0000000..99ca271
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/Sources.java
@@ -0,0 +1,54 @@
+package ru.mipt.diht.students.annnvl.CQL;
+
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * Helper methods to create collections.
+ */
+public class Sources {
+
+ /**
+ * @param items
+ * @param
+ * @return
+ */
+ @SafeVarargs
+ public static List list(T... items) {
+ return Arrays.asList(items);
+ }
+
+ /**
+ * @param items
+ * @param
+ * @return
+ */
+ @SafeVarargs
+ public static Set set(T... items) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @param inputStream
+ * @param
+ * @return
+ */
+ public static Stream lines(InputStream inputStream) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @param file
+ * @param
+ * @return
+ */
+ public static Stream lines(Path file) {
+ throw new UnsupportedOperationException();
+ }
+
+}
+
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Aggregator.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Aggregator.java
new file mode 100644
index 0000000..11ba369
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Aggregator.java
@@ -0,0 +1,8 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.List;
+import java.util.function.Function;
+
+public interface Aggregator extends Function {
+ R apply(List elements);
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Avg.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Avg.java
new file mode 100644
index 0000000..dc79538
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Avg.java
@@ -0,0 +1,27 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class Avg implements Aggregator {
+
+ private Function function;
+ public Avg(Function expression) {
+ this.function = expression;
+ }
+
+ @Override
+ public Double apply(List elements) {
+ return elements
+ .stream()
+ .map(function)
+ .mapToDouble(element -> (Double) element)
+ .average()
+ .getAsDouble();
+ }
+
+ @Override
+ public Double apply(T t) {
+ return null;
+ }
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Count.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Count.java
new file mode 100644
index 0000000..8553f70
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Count.java
@@ -0,0 +1,26 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class Count implements Aggregator {
+
+ private Function function;
+ public Count(Function expression) {
+ this.function = expression;
+ }
+
+ @Override
+ public Integer apply(List elements) {
+ Long longAns = elements
+ .stream()
+ .map(function)
+ .distinct()
+ .count();
+ return longAns.intValue();
+ }
+ @Override
+ public Integer apply(T t) {
+ return null;
+ }
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/FromStmt.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/FromStmt.java
new file mode 100644
index 0000000..308073e
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/FromStmt.java
@@ -0,0 +1,91 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+public class FromStmt {
+
+ private List elements = new ArrayList();
+
+ public FromStmt(Iterable iterable) {
+ for (T element : iterable) {
+ elements.add(element);
+ }
+ }
+
+ public static FromStmt from(Iterable iterable) {
+ return new FromStmt<>(iterable);
+ }
+
+ @SafeVarargs
+ public final SelectStmt select(Class returnClass, Function... functions) {
+ return new SelectStmt<>(elements, returnClass, false, functions);
+ }
+
+ @SafeVarargs
+ public final SelectStmt selectDistinct(Class returnClass, Function... functions) {
+ return new SelectStmt<>(elements, returnClass, true, functions);
+ }
+
+ public final SelectStmt> select(Function first, Function second) {
+ return new SelectStmt<>(elements, false, first, second);
+ }
+
+ public JoinClause join(Iterable iterable) {
+ return new JoinClause(elements, iterable);
+ }
+
+ public class JoinClause {
+
+
+ private List firstElements = new ArrayList<>();
+ private List secondElements = new ArrayList<>();
+ private List> elements = new ArrayList<>();
+
+ public JoinClause(List firstElements, Iterable secondElements) {
+ this.firstElements.addAll(firstElements);
+ secondElements.forEach(this.secondElements::add);
+ }
+
+ public FromStmt> on(BiPredicate condition) {
+ for (S first : firstElements) {
+ for (J second : secondElements) {
+ if (condition.test(first, second)) {
+ elements.add(new Tuple<>(first, second));
+ }
+ }
+ }
+ return new FromStmt<>(elements);
+ }
+
+ public > FromStmt> on(
+ Function leftKey,
+ Function rightKey) {
+ HashMap> map = new HashMap<>();
+ for (J element : secondElements) {
+ K key = rightKey.apply(element);
+ if (!map.containsKey(key)) {
+ map.put(key, new ArrayList<>());
+ }
+ map.get(key).add(element);
+ }
+ for (S first : firstElements) {
+ K key = leftKey.apply(first);
+ if (map.containsKey(key)) {
+ List second = map.get(key);
+ second.forEach(s -> elements.add(new Tuple<>(first, s)));
+ }
+ }
+ return new FromStmt<>(elements);
+ }
+ }
+
+ public List getElements() {
+ return elements;
+ }
+}
+
+
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Max.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Max.java
new file mode 100644
index 0000000..4133fae
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Max.java
@@ -0,0 +1,37 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class Max> implements Aggregator {
+
+ private Function function;
+ public Max(Function expression) {
+ this.function = expression;
+ }
+
+ @Override
+ public R apply(List elements) {
+ return elements
+ .stream()
+ .map(function)
+ .reduce(null, (a, b) -> {
+ if (a == null) {
+ return b;
+ }
+ if (b == null) {
+ return a;
+ }
+ if (a.compareTo(b) > 0) {
+ return a;
+ } else {
+ return b;
+ }
+ });
+ }
+
+ @Override
+ public R apply(T t) {
+ return null;
+ }
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Min.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Min.java
new file mode 100644
index 0000000..a737cd6
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Min.java
@@ -0,0 +1,38 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.util.List;
+import java.util.function.Function;
+
+public class Min> implements Aggregator {
+
+ private Function function;
+ public Min(Function expression) {
+ this.function = expression;
+ }
+
+ @Override
+ public R apply(List elements) {
+ return elements
+ .stream()
+ .map(function)
+
+ .reduce(null, (a, b) -> {
+ if (a == null) {
+ return b;
+ }
+ if (b == null) {
+ return a;
+ }
+ if (a.compareTo(b) < 0) {
+ return a;
+ } else {
+ return b;
+ }
+ });
+ }
+
+ @Override
+ public R apply(T t) {
+ return null;
+ }
+}
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Query.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Query.java
new file mode 100644
index 0000000..3b94998
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/Query.java
@@ -0,0 +1,13 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.stream.Stream;
+
+public interface Query {
+
+ Iterable execute() throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException;
+
+ Stream stream();
+}
+
diff --git a/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/SelectStmt.java b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/SelectStmt.java
new file mode 100644
index 0000000..54c57de
--- /dev/null
+++ b/projects/annnvl/src/main/java/ru/mipt/diht/students/annnvl/CQL/impl/SelectStmt.java
@@ -0,0 +1,230 @@
+package ru.mipt.diht.students.annnvl.CQL.impl;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class SelectStmt {
+
+ private boolean isDistinct;
+ private Class returnClass;
+ private Function[] functions;
+ private List elements;
+
+ private List pastElements;
+
+ private Predicate whereCondition;
+ private Comparator[] comparators;
+ private Predicate havingCondition;
+ private int numberOfObjects;
+ private Function[] groupByConditions;
+
+ private CQLComparator cqlComparator;
+ private boolean isUnion;
+ private boolean isJoin;
+
+ @SafeVarargs
+ public SelectStmt(List elements, Class returnClass, boolean isDistinct, Function... functions) {
+ this.elements = new ArrayList<>();
+ this.elements.addAll(elements);
+ this.returnClass = returnClass;
+ this.isDistinct = isDistinct;
+ this.functions = functions;
+ this.numberOfObjects = -1;
+ this.isUnion = false;
+ this.isJoin = false;
+ }
+
+ public SelectStmt(List elements, boolean isDistinct, Function first, Function second) {
+ this.elements = new ArrayList<>();
+ this.elements.addAll(elements);
+ this.returnClass = elements.get(0).getClass();
+ this.isDistinct = isDistinct;
+ this.functions = new Function[]{first, second};
+ this.numberOfObjects = -1;
+ this.isUnion = false;
+ this.isJoin = true;
+ }
+
+ @SafeVarargs
+ public SelectStmt(List pastElements, List elements, Class returnClass,
+ boolean isDistinct, Function... functions) {
+ this.elements = new ArrayList<>();
+ this.elements.addAll(elements);
+ this.returnClass = returnClass;
+ this.isDistinct = isDistinct;
+ this.functions = functions;
+ this.numberOfObjects = -1;
+ this.isUnion = true;
+ this.pastElements = pastElements;
+ }
+
+ public SelectStmt(List pastElements, List elements, boolean isDistinct, Function first,
+ Function second) {
+ this.elements = new ArrayList<>();
+ this.elements.addAll(elements);
+ this.returnClass = elements.get(0).getClass();
+ this.isDistinct = isDistinct;
+ this.functions = new Function[]{first, second};
+ this.numberOfObjects = -1;
+ this.isUnion = true;
+ this.isJoin = true;
+ this.pastElements = pastElements;
+ }
+
+ public SelectStmt where(Predicate predicate) {
+ this.whereCondition = predicate;
+ return this;
+ }
+
+ @SafeVarargs
+ public final SelectStmt groupBy(Function... expressions) {
+ groupByConditions = expressions;
+ //groupByConditions = Arrays.asList(expressions);
+ return this;
+ }
+
+ @SafeVarargs
+ public final SelectStmt orderBy(Comparator... comparators) {
+ this.comparators = comparators;
+ this.cqlComparator = new CQLComparator(comparators);
+ return this;
+ }
+
+ public SelectStmt having(Predicate condition) {
+ this.havingCondition = condition;
+ return this;
+ }
+
+ public SelectStmt limit(int amount) {
+ this.numberOfObjects = amount;
+ return this;
+ }
+
+ public Iterable execute() throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException, InstantiationException {
+ List result = new ArrayList<>();
+ Class[] returnClasses = new Class[functions.length];
+ if (whereCondition != null) {
+ elements = elements
+ .stream()
+ .filter(whereCondition::test)
+ .collect(Collectors.toList());
+ }
+ if (groupByConditions != null) {
+
+ Map> groupedMap = elements
+ .stream()
+ .collect(Collectors.groupingBy((T element) -> {
+ List