All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jinq.orm.stream.JinqStream Maven / Gradle / Ivy

package org.jinq.orm.stream;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

import org.jinq.tuples.Pair;
import org.jinq.tuples.Tuple3;
import org.jinq.tuples.Tuple4;
import org.jinq.tuples.Tuple5;

public interface JinqStream extends Stream
{
   public static interface Where extends Serializable {
      public boolean where(U obj) throws E;
   }
   public  JinqStream where(Where test);
   public static interface Select extends Serializable {
      public V select(U val);
   }
   public  JinqStream select(Select select);
   // TODO: Joins are somewhat dangerous because certain types of joins that are
   // expressible here are NOT expressible in SQL. (Moving a join into
   // a from clause is only possible if the join does not access variables from
   // other things in the FROM clause *if* it ends up as a subquery. If we can 
   // express it as not a subquery, then it's ok.
   // TODO: Perhaps only providing a join(DBSet other) is safer because
   // I think it will translate into valid SQL code, but it prevents people from
   // using navigational queries e.g. customers.join(customer -> customer.getPurchases);
   public static interface Join extends Serializable {
      public JinqStream join(U val);
   }
   public  JinqStream> join(Join join);
   public static interface JoinWithSource extends Serializable {
      public JinqStream join(U val, InQueryStreamSource source);
   }
   public  JinqStream> join(JoinWithSource join);
   public JinqStream unique();
   public static interface AggregateGroup extends Serializable {
      public V aggregateSelect(W key, JinqStream val);
   }
   public  JinqStream> group(Select select, AggregateGroup aggregate);
   /** @see #group(Select, AggregateGroup) */
   public  JinqStream> group(Select select, 
         AggregateGroup aggregate1, AggregateGroup aggregate2);
   /** @see #group(Select, AggregateGroup) */
   public  JinqStream> group(Select select, 
         AggregateGroup aggregate1, AggregateGroup aggregate2,
         AggregateGroup aggregate3);
   /** @see #group(Select, AggregateGroup) */
   public  JinqStream> group(Select select, 
         AggregateGroup aggregate1, AggregateGroup aggregate2,
         AggregateGroup aggregate3, AggregateGroup aggregate4);

   
   // TODO: This interface is a little iffy since the function can potentially return different number types
   // and things can't be checked until runtime, but Java type inferencing currently can't
   // disambiguate between different methods that take functions with different return types.
   // In most cases, this should be fine as long as programmers define V as something specific
   // like Integer or Double instead of something generic like Number.

   // These interfaces are used to define the lambdas used as parameters to various aggregation
   // operations.
   public static interface CollectNumber> extends Serializable {
      public V aggregate(U val);
   }
   public static interface CollectComparable> extends Serializable {
      public V aggregate(U val);
   }
   public static interface CollectInteger extends CollectNumber {}
   public static interface CollectLong extends CollectNumber {}
   public static interface CollectDouble extends CollectNumber {}
   public static interface CollectBigDecimal extends CollectNumber {}
   public static interface CollectBigInteger extends CollectNumber {}
   
   // Having separate sum() methods for different types is messy but due to problems
   // with Java's type inferencing and the fact that JPQL uses different return types
   // for a sum than the types being summed over, this is the only way to do sum
   // operations in a type-safe way.
   public Long sumInteger(CollectInteger aggregate);
   public Long sumLong(CollectLong aggregate);
   public Double sumDouble(CollectDouble aggregate);
   public BigDecimal sumBigDecimal(CollectBigDecimal aggregate);
   public BigInteger sumBigInteger(CollectBigInteger aggregate);
   

   // TODO: It's more type-safe to have separate maxDouble(), maxDate(), etc. methods,
   // but it's too messy, so I'll provide this simpler max() method for now
   public > V max(CollectComparable aggregate);
   public > V min(CollectComparable aggregate);
   public > Double avg(CollectNumber aggregate);
   
   public static interface AggregateSelect extends Serializable {
      public V aggregateSelect(JinqStream val);
   }
//   public  U selectAggregates(AggregateSelect aggregate);
//   public  U aggregate(AggregateSelect aggregate1);
   public  Pair aggregate(AggregateSelect aggregate1,
         AggregateSelect aggregate2);
   /**
    * @see #aggregate(AggregateSelect, AggregateSelect)
    */
   public  Tuple3 aggregate(AggregateSelect aggregate1,
         AggregateSelect aggregate2, AggregateSelect aggregate3);
   /**
    * @see #aggregate(AggregateSelect, AggregateSelect)
    */
   public  Tuple4 aggregate(AggregateSelect aggregate1,
         AggregateSelect aggregate2, AggregateSelect aggregate3,
         AggregateSelect aggregate4);
   /**
    * @see #aggregate(AggregateSelect, AggregateSelect)
    */
   public  Tuple5 aggregate(AggregateSelect aggregate1,
         AggregateSelect aggregate2, AggregateSelect aggregate3,
         AggregateSelect aggregate4, AggregateSelect aggregate5);

   public > JinqStream sortedBy(CollectComparable sortField);
   public > JinqStream sortedDescendingBy(CollectComparable sortField);
   
   // Overriding the Stream API versions to return a JinqStream instead, so it's easier to chain them
   @Override public JinqStream skip(long n);
   @Override public JinqStream limit(long n);

   public T getOnlyValue();
   public JinqStream with(T toAdd);
   
   // TODO: Should toList() throw an exception?
   public List toList();
   
   public String getDebugQueryString();
   
   /**
    * Used for recording an exception that occurred during processing
    * somewhere in the stream chain.
    *  
    * @param source lambda object that caused the exception (used so that
    *    if the same lambda causes multiple exceptions, only some of them 
    *    need to be recorded in order to avoid memory issues)
    * @param exception actual exception object
    */
   public void propagateException(Object source, Throwable exception);
   
   public Collection getExceptions();
   
   /**
    * Sets a hint on the stream for how the query should be executed
    * @param name
    * @param value
    * @return this
    */
   public JinqStream setHint(String name, Object value);
   
   /**
    * Easy way to get a JinqStream from a collection. 
    */
   public static  JinqStream from(Collection collection)
   {
      return new NonQueryJinqStream<>(collection.stream());
   }
}