package eu.eudat.queryable;

import eu.eudat.queryable.jpa.predicates.*;
import eu.eudat.queryable.queryableentity.DataEntity;
import eu.eudat.queryable.types.SelectionField;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Subquery;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public interface QueryableList<T extends DataEntity> {
    QueryableList<T> where(SinglePredicate<T> predicate);

    <R> List<R> select(SelectPredicate<T, R> predicate);

    <R> CompletableFuture<List<R>> selectAsync(SelectPredicate<T, R> predicate);

    List<T> toList();

    <V> void update(EntitySelectPredicate<T> selectPredicate, V value);

    QueryableList<T> withFields(List<String> fields);

    List<Map> toListWithFields();

    CompletableFuture<List<T>> toListAsync();

    T getSingle();

    CompletableFuture<T> getSingleAsync();

    T getSingleOrDefault();

    CompletableFuture<T> getSingleOrDefaultAsync();

    QueryableList<T> skip(Integer offset);

    QueryableList<T> take(Integer length);

    QueryableList<T> distinct();

    QueryableList<T> orderBy(OrderByPredicate<T> predicate);

    QueryableList<T> groupBy(GroupByPredicate<T> predicate);

    QueryableList<T> withHint(String hint);

    Long count();

    QueryableList<T> where(NestedQuerySinglePredicate<T> predicate);

    CompletableFuture<Long> countAsync();

    Subquery<T> query(List<SelectionField> fields);

    Subquery<T> subQuery(SinglePredicate<T> predicate, List<SelectionField> fields);

    Subquery<T> subQuery(NestedQuerySinglePredicate<T> predicate, List<SelectionField> fields);

    Subquery<Long> subQueryCount(NestedQuerySinglePredicate<T> predicate, List<SelectionField> fields);

    Subquery<Long> subQueryCount(SinglePredicate<T> predicate, List<SelectionField> fields);

    <U> QueryableList<T> initSubQuery(Class<U> uClass);

    <U extends Comparable> Subquery<U> subQueryMax(SinglePredicate<T> predicate, List<SelectionField> fields, Class<U> uClass);

    <U extends Comparable> Subquery<U> subQueryMax(NestedQuerySinglePredicate<T> predicate, List<SelectionField> fields, Class<U> uClass);

    Join getJoin(String field, JoinType type);


}
