WindowFunctionFramable.java
/*
* Copyright 2019 Gregory Graham.
*
* Commercial licenses are available, please contact info@gregs.co.nz for details.
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
* or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
*
* You are free to:
* Share - copy and redistribute the material in any medium or format
* Adapt - remix, transform, and build upon the material
*
* The licensor cannot revoke these freedoms as long as you follow the license terms.
* Under the forFollowing terms:
*
* Attribution -
* You must give appropriate credit, provide a link to the license, and indicate if changes were made.
* You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
* NonCommercial -
* You may not use the material for commercial purposes.
* ShareAlike -
* If you remix, transform, or build upon the material,
* you must distribute your contributions under the same license as the original.
* No additional restrictions -
* You may not apply legal terms or technological measures that legally restrict others from doing anything the
* license permits.
*
* Check the Creative Commons website for any details, legalese, and updates.
*/
package nz.co.gregs.dbvolution.expressions.windows;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import nz.co.gregs.dbvolution.DBRow;
import nz.co.gregs.dbvolution.columns.ColumnProvider;
import nz.co.gregs.dbvolution.databases.DBDatabase;
import nz.co.gregs.dbvolution.databases.definitions.DBDefinition;
import nz.co.gregs.dbvolution.datatypes.QueryableDatatype;
import nz.co.gregs.dbvolution.expressions.BooleanExpression;
import nz.co.gregs.dbvolution.expressions.EqualExpression;
import nz.co.gregs.dbvolution.expressions.IntegerExpression;
import nz.co.gregs.dbvolution.expressions.SortProvider;
import nz.co.gregs.dbvolution.results.AnyResult;
/**
*
* @author gregorygraham
* @param <A> the expression type returned by this windowing function, e.g.
* IntegerExpression
*/
public class WindowFunctionFramable<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface<A> {
private final A innerExpression;
public WindowFunctionFramable(A expression) {
super();
this.innerExpression = expression;
}
@Override
public Partitioned<A> partition(EqualExpression<?,?,?>... cols) {
return new WindowFunctionFramable.Partitioned<A>(this, cols);
}
@Override
public Partitioned<A> unpartitioned() {
return new WindowFunctionFramable.Partitioned<A>(this);
}
public A allRows() {
return this.partition().unsorted();
}
public A getInnerExpression() {
return innerExpression;
}
public A allRowsPreceding() {
return this.partition().unsortedWithFrame().rows().unboundedPrecedingAndCurrentRow();
}
public A AllRowsAndOrderBy(SortProvider... sorts) {
if (sorts.length > 0) {
return this.partition().orderBy(sorts).rows().unboundedPreceding().currentRow();
} else {
return this.partition().unsorted();
}
}
@Override
public String toSQLString(DBDefinition defn) {
return innerExpression.toSQLString(defn) + " OVER (";
}
@SuppressWarnings("unchecked")
@Override
public Class<A> getRequiredExpressionClass() {
return (Class<A>) innerExpression.getClass();
}
@SuppressWarnings("unchecked")
@Override
public WindowFunctionFramable<A> copy() {
return new WindowFunctionFramable<A>((A) this.innerExpression.copy());
}
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
throw new UnsupportedOperationException("WindowFunctionFramable does not support isAggregator() yet.");
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable does not support getTablesInvolved() yet.");
}
@Override
public boolean isPurelyFunctional() {
boolean functional = innerExpression.isPurelyFunctional();
return functional;
}
@Override
public boolean isComplexExpression() {
throw new UnsupportedOperationException("WindowFunctionFramable does not support isComplexExpression() yet.");
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
throw new UnsupportedOperationException("WindowFunctionFramable does not support isWindowingFunction() yet.");
}
public static class Partitioned<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface.Partitioned<A> {
private final WindowFunctionFramable<A> innerExpression;
private final EqualExpression<?, ?, ?>[] partitionExpressions;
private Partitioned(WindowFunctionFramable<A> expression, EqualExpression<?,?,?>... cols) {
super();
this.innerExpression = expression;
this.partitionExpressions = cols;
}
private Partitioned(WindowFunctionFramable<A> expression) {
super();
this.innerExpression = expression;
this.partitionExpressions = new EqualExpression<?,?,?>[]{};
}
@Override
public WindowFunctionFramable.Sorted<A> orderBy(SortProvider... sorts) {
if (sorts.length == 0) {
return new UnSorted<A>(this);
} else {
return new WindowFunctionFramable.Sorted<A>(this, sorts);
}
}
@Override
public String toSQLString(DBDefinition defn) {
StringBuilder partitionClause = new StringBuilder();
if (getPartitionExpressions().length > 0) {
partitionClause.append("PARTITION BY ");
String separator = "";
for (EqualExpression<?,?,?> partitionByColumn : getPartitionExpressions()) {
partitionClause.append(separator).append(partitionByColumn.toSQLString(defn));
separator = ", ";
}
}
return getInnerExpression().toSQLString(defn) + partitionClause;
}
@Override
public Class<A> getRequiredExpressionClass() {
return getInnerExpression().getRequiredExpressionClass();
}
@SuppressWarnings("unchecked")
@Override
public Partitioned<A> copy() {
return new Partitioned<A>(this.getInnerExpression().copy(), this.getPartitionExpressions());
}
@Override
@SuppressWarnings("unchecked")
public A unsorted() {
final Sorted<A> orderBy = new UnSorted<A>(this);
return orderBy.withoutFrame();
}
@SuppressWarnings("unchecked")
@Override
public Sorted<A> unsortedWithFrame() {
return this.orderBy(BooleanExpression.trueExpression().ascending());
}
@Override
@SuppressWarnings("unchecked")
public A unordered() {
return unsorted();
}
@Override
@SuppressWarnings("unchecked")
public Sorted<A> unorderedWithFrame() {
return unsortedWithFrame();
}
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support isAggregator() yet.");
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support getTablesInvolved() yet.");
}
@Override
public boolean isPurelyFunctional() {
boolean functional = getInnerExpression().isPurelyFunctional();
if (functional == true) {
for (EqualExpression<?,?,?> column : getPartitionExpressions()) {
functional = functional && column.isPurelyFunctional();
}
}
return functional;
}
@Override
public boolean isComplexExpression() {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support isComplexExpression() yet.");
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support isWindowingFunction() yet.");
}
@Override
public Sorted<A> orderByWithPrimaryKeys(SortProvider... partitionFields) {
throw new UnsupportedOperationException("WindowFunctionFramable.Partitioned does not support orderByWithPrimaryKeys(SortProvider...) yet.");
}
@Override
public Sorted<A> orderByWithPrimaryKeys(ColumnProvider... partitionFields) {
return orderByWithPrimaryKeys(SortProvider.getSortProviders(partitionFields));
}
/**
* @return the innerExpression
*/
protected WindowFunctionFramable<A> getInnerExpression() {
return innerExpression;
}
/**
* @return the expressions used in the partition clause
*/
protected EqualExpression<?,?,?>[] getPartitionExpressions() {
return partitionExpressions;
}
private class UnSorted<A extends EqualExpression<?, ?, ?>> extends Sorted<A> {
public UnSorted(Partitioned<A> expression) {
super(expression, BooleanExpression.trueExpression().ascending());
}
@Override
public String toSQLString(DBDefinition defn) {
if (defn.supportsComparingBooleanResults()) {
return super.toSQLString(defn);
} else {
return getInnerExpression().toSQLString(defn);
}
}
}
}
public static class Sorted<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface.Sorted<A> {
private final WindowFunctionFramable.Partitioned<A> innerExpression;
private final SortProvider[] sorts;
public Sorted(WindowFunctionFramable.Partitioned<A> expression, SortProvider... sorts) {
super();
this.innerExpression = expression;
this.sorts = sorts;
}
@Override
public String toSQLString(DBDefinition defn) {
StringBuilder orderByClause = new StringBuilder();
if (getSorts().length > 0) {
orderByClause.append(" ORDER BY ");
String separator = "";
for (SortProvider partitionByColumn : getSorts()) {
orderByClause.append(separator).append(partitionByColumn.toSQLString(defn));
separator = ", ";
}
}
return getInnerExpression().toSQLString(defn) + orderByClause;
}
public A defaultFrame() {
return this.withoutFrame();
}
@Override
public A withoutFrame() {
return new EmptyFrameEnd<>(this).build();
}
@Override
public Rows<A> rows() {
return new Rows<A>(this);
}
/* MS SQL Server 2017 does not support groups */
// @Override
// public Groups<A> groups() {
// return new Groups<A>(this);
// }
@Override
public Range<A> range() {
return new Range<A>(this);
}
@Override
public Class<A> getRequiredExpressionClass() {
return getInnerExpression().getRequiredExpressionClass();
}
@SuppressWarnings("unchecked")
@Override
public Sorted<A> copy() {
return new Sorted<A>(this.getInnerExpression().copy(), this.getSorts());
}
@Override
public boolean isPurelyFunctional() {
boolean functional = getInnerExpression().isPurelyFunctional();
if (functional == true) {
for (SortProvider sort : getSorts()) {
functional = functional && sort.isPurelyFunctional();
}
}
return functional;
}
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support isAggregator() yet.");
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support getTablesInvolved() yet.");
}
@Override
public boolean isComplexExpression() {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support isComplexExpression() yet.");
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
throw new UnsupportedOperationException("WindowFunctionFramable.Sorted does not support isWindowingFunction() yet.");
}
/**
* @return the innerExpression
*/
protected WindowFunctionFramable.Partitioned<A> getInnerExpression() {
return innerExpression;
}
/**
* @return the sorts
*/
protected SortProvider[] getSorts() {
return sorts;
}
}
public static abstract class FrameType<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface.FrameType<A> {
private final Sorted<A> sorted;
public FrameType(Sorted<A> sorted) {
super();
this.sorted = sorted;
}
protected Sorted<A> getSorted() {
return sorted;
}
public A unboundedPrecedingAndCurrentRow() {
return this.unboundedPreceding().currentRow();
}
public A offsetPrecedingAndCurrentRow(int offset) {
return this.preceding(offset).currentRow();
}
public A offsetPrecedingAndCurrentRow(IntegerExpression offset) {
return this.preceding(offset).currentRow();
}
public A onlyCurrentRow() {
return this.currentRow().toCurrentRow();
}
@Override
public UnboundedPrecedingStart<A> unboundedPreceding() {
return new UnboundedPrecedingStart<A>(this);
}
@Override
public OffsetPrecedingStart<A> preceding(int offset) {
return new OffsetPrecedingStart<A>(this, offset);
}
@Override
public OffsetPrecedingStart<A> preceding(IntegerExpression offset) {
return new OffsetPrecedingStart<A>(this, offset);
}
@Override
public CurrentRowStart<A> currentRow() {
return new CurrentRowStart<A>(this);
}
@Override
public OffsetFollowingStart<A> forFollowing(int offset) {
return new OffsetFollowingStart<A>(this, offset);
}
@Override
public OffsetFollowingStart<A> forFollowing(IntegerExpression offset) {
return new OffsetFollowingStart<A>(this, offset);
}
@Override
public Class<A> getRequiredExpressionClass() {
return sorted.getRequiredExpressionClass();
}
@Override
public abstract FrameType<A> copy();
@Override
public final boolean isPurelyFunctional() {
return getSorted().isPurelyFunctional();
}
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support isAggregator() yet.");
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support getTablesInvolved() yet.");
}
@Override
public boolean isComplexExpression() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support isComplexExpression() yet.");
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameType does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
return true;
}
}
public static class Range<A extends EqualExpression<?, ?, ?>> extends FrameType<A> {
public Range(Sorted<A> sorted) {
super(sorted);
}
@Override
public String toSQLString(DBDefinition defn) {
return getSorted().toSQLString(defn) + " RANGE BETWEEN ";
}
@Override
@SuppressWarnings("unchecked")
public Range<A> copy() {
return new Range<A>(this.getSorted().copy());
}
}
public static class Rows<A extends EqualExpression<?, ?, ?>> extends FrameType<A> {
public Rows(Sorted<A> sorted) {
super(sorted);
}
@Override
public String toSQLString(DBDefinition defn) {
return getSorted().toSQLString(defn) + " ROWS BETWEEN ";
}
@Override
@SuppressWarnings("unchecked")
public Rows<A> copy() {
return new Rows<A>(this.getSorted().copy());
}
}
public static class Groups<A extends EqualExpression<?, ?, ?>> extends FrameType<A> {
public Groups(Sorted<A> sorted) {
super(sorted);
}
@Override
public String toSQLString(DBDefinition defn) {
return getSorted().toSQLString(defn) + " GROUPS BETWEEN ";
}
@Override
@SuppressWarnings("unchecked")
public Groups<A> copy() {
return new Groups<A>(this.getSorted().copy());
}
}
public static abstract class FrameStart<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface.EmptyFrameStart<A> {
protected final FrameType<A> type;
protected final IntegerExpression offset;
public FrameStart(FrameType<A> type) {
super();
this.type = type;
this.offset = IntegerExpression.value(1);
}
public FrameStart(FrameType<A> type, int offset) {
super();
this.type = type;
this.offset = IntegerExpression.value(offset);
}
public FrameStart(FrameType<A> type, long offset) {
super();
this.type = type;
this.offset = IntegerExpression.value(offset);
}
public FrameStart(FrameType<A> type, IntegerExpression offset) {
super();
this.type = type;
this.offset = offset;
}
@Override
public Class<A> getRequiredExpressionClass() {
return type.getRequiredExpressionClass();
}
@SuppressWarnings("unchecked")
@Override
public abstract FrameStart<A> copy();
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support isAggregator() yet.");
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support getTablesInvolved0() yet.");
}
@Override
public boolean isComplexExpression() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support isComplexExpression() yet.");
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameStart does not support isWindowingFunction() yet.");
}
}
private static abstract class FrameStartAbsolute<A extends EqualExpression<?, ?, ?>> extends FrameStart<A> {
public FrameStartAbsolute(FrameType<A> type) {
super(type);
}
@Override
public final boolean isPurelyFunctional() {
return type.isPurelyFunctional();
}
}
private static abstract class FrameStartOffset<A extends EqualExpression<?, ?, ?>> extends FrameStart<A> {
public FrameStartOffset(FrameType<A> type, int offset) {
super(type, offset);
}
public FrameStartOffset(FrameType<A> type, long offset) {
super(type, offset);
}
public FrameStartOffset(FrameType<A> type, IntegerExpression offset) {
super(type, offset);
}
public FrameStartOffset(FrameType<A> type) {
super(type);
}
@Override
public final boolean isPurelyFunctional() {
return type.isPurelyFunctional() && offset.isPurelyFunctional();
}
}
public static class UnboundedPrecedingStart<A extends EqualExpression<?, ?, ?>> extends FrameStartAbsolute<A> implements FrameStartAllPreceding<A> {
public UnboundedPrecedingStart(FrameType<A> type) {
super(type);
}
@Override
public String toSQLString(DBDefinition defn) {
return type.toSQLString(defn) + " UNBOUNDED PRECEDING ";
}
@Override
public UnboundedPrecedingStart<A> copy() {
return new UnboundedPrecedingStart<>(type.copy());
}
@Override
@SuppressWarnings("unchecked")
public A preceding(int offset) {
return new OffsetPrecedingEnd<A>(this, offset).build();
}
@Override
public A preceding(IntegerExpression offset) {
return new OffsetPrecedingEnd<A>(this, offset).build();
}
@Override
public A currentRow() {
return new CurrentRowEnd<A>(this).build();
}
@Override
public A forFollowing(int offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A forFollowing(IntegerExpression offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A unboundedFollowing() {
return new UnboundedFollowingEnd<A>(this).build();
}
}
public static class OffsetPrecedingStart<A extends EqualExpression<?, ?, ?>> extends FrameStartOffset<A> implements FrameStartPreceding<A> {
public OffsetPrecedingStart(FrameType<A> type, int offset) {
super(type, offset);
}
public OffsetPrecedingStart(FrameType<A> type, long offset) {
super(type, offset);
}
public OffsetPrecedingStart(FrameType<A> type, IntegerExpression offset) {
super(type, offset);
}
@Override
public String toSQLString(DBDefinition defn) {
return type.toSQLString(defn) + " " + offset.toSQLString(defn) + " PRECEDING ";
}
@Override
public A preceding(int offset) {
return new OffsetPrecedingEnd<A>(this, offset).build();
}
@Override
public A preceding(IntegerExpression offset) {
return new OffsetPrecedingEnd<A>(this, offset).build();
}
@Override
public OffsetPrecedingStart<A> copy() {
return new OffsetPrecedingStart<>(type.copy(), offset.copy());
}
@Override
public A currentRow() {
return new CurrentRowEnd<A>(this).build();
}
@Override
public A forFollowing(int offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A forFollowing(IntegerExpression offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A unboundedFollowing() {
return new UnboundedFollowingEnd<A>(this).build();
}
}
public static class CurrentRowStart<A extends EqualExpression<?, ?, ?>> extends FrameStartAbsolute<A> implements FrameStartCurrentRow<A> {
public CurrentRowStart(FrameType<A> type) {
super(type);
}
@Override
public String toSQLString(DBDefinition defn) {
return type.toSQLString(defn) + " CURRENT ROW ";
}
@Override
public CurrentRowStart<A> copy() {
return new CurrentRowStart<>(type.copy());
}
@Override
public A toCurrentRow() {
return new CurrentRowEnd<A>(this).build();
}
@Override
public A forFollowing(int offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A forFollowing(IntegerExpression offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A unboundedFollowing() {
return new UnboundedFollowingEnd<A>(this).build();
}
}
public static class OffsetFollowingStart<A extends EqualExpression<?, ?, ?>> extends FrameStartOffset<A> implements FrameStartFollowing<A> {
public OffsetFollowingStart(FrameType<A> type, int offset) {
super(type, offset);
}
public OffsetFollowingStart(FrameType<A> type, long offset) {
super(type, offset);
}
public OffsetFollowingStart(FrameType<A> type, IntegerExpression offset) {
super(type, offset);
}
@Override
public String toSQLString(DBDefinition defn) {
return type.toSQLString(defn) + " " + offset.toSQLString(defn) + " FOLLOWING ";
}
@Override
public OffsetFollowingStart<A> copy() {
return new OffsetFollowingStart<>(type.copy(), offset.copy());
}
@Override
public A forFollowing(int offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A forFollowing(IntegerExpression offset) {
return new OffsetFollowingEnd<A>(this, offset).build();
}
@Override
public A unboundedFollowing() {
return new UnboundedFollowingEnd<A>(this).build();
}
}
public static abstract class FrameEnd<A extends EqualExpression<?, ?, ?>> implements WindowingFunctionFramableInterface.WindowEnd<A>, AnyResult<A> {
private final WindowPart<A> start;
private final IntegerExpression offset;
protected FrameEnd(WindowPart<A> start) {
this.start = start;
this.offset = IntegerExpression.value(0);
}
protected FrameEnd(WindowPart<A> start, int offset) {
this.start = start;
this.offset = IntegerExpression.value(offset);
}
protected FrameEnd(WindowPart<A> start, IntegerExpression offset) {
this.start = start;
this.offset = offset;
}
/**
* @return the and
*/
protected WindowPart<A> getStart() {
return start;
}
/**
* @return the offset
*/
protected IntegerExpression getOffset() {
return offset;
}
@Override
public A build() {
try {
final Class<A> clazz = getStart().getRequiredExpressionClass();
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0].equals(AnyResult.class)) {
constructor.setAccessible(true);
@SuppressWarnings("unchecked")
A newInstance = (A) constructor.newInstance((AnyResult) this);
return newInstance;
}
}
} catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(WindowFunctionFramable.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public QueryableDatatype<?> getQueryableDatatypeForExpressionValue() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameEnd does not support getQueryableDatatypeForExpressionValue() yet.");
}
@Override
public boolean isAggregator() {
return false;
}
@Override
public Set<DBRow> getTablesInvolved() {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameEnd does not support getTablesInvolved() yet.");
}
@Override
public boolean isComplexExpression() {
return false;
}
@Override
public String createSQLForFromClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameEnd does not support createSQLForFromClause(DBDatabase) yet.");
}
@Override
public String createSQLForGroupByClause(DBDatabase database) {
throw new UnsupportedOperationException("WindowFunctionFramable.FrameEnd does not support createSQLForGroupByClause(DBDatabase) yet.");
}
@Override
public boolean isWindowingFunction() {
return true;
}
@Override
public boolean getIncludesNull() {
return true;
}
}
public static class UnboundedPrecedingEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public UnboundedPrecedingEnd(FrameStart<A> start) {
super(start);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " AND UNBOUNDED PRECEDING )";
}
@Override
public UnboundedPrecedingEnd<A> copy() {
return new UnboundedPrecedingEnd<A>((FrameStart<A>) getStart().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional();
}
}
public static class OffsetPrecedingEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public OffsetPrecedingEnd(FrameStart<A> aThis, int offset) {
super(aThis, offset);
}
public OffsetPrecedingEnd(FrameStart<A> aThis, IntegerExpression offset) {
super(aThis, offset);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " AND " + getOffset().toSQLString(defn) + " PRECEDING )";
}
@Override
public OffsetPrecedingEnd<A> copy() {
return new OffsetPrecedingEnd<A>((FrameStart<A>) getStart().copy(), getOffset().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional() && getOffset().isPurelyFunctional();
}
}
public static class CurrentRowEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public CurrentRowEnd(FrameStart<A> start) {
super(start);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " AND CURRENT ROW )";
}
@Override
public CurrentRowEnd<A> copy() {
return new CurrentRowEnd<A>((FrameStart<A>) getStart().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional();
}
}
private static class OffsetFollowingEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public OffsetFollowingEnd(FrameStart<A> aThis, int offset) {
super(aThis, offset);
}
public OffsetFollowingEnd(FrameStart<A> aThis, IntegerExpression offset) {
super(aThis, offset);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " AND " + getOffset().toSQLString(defn) + " FOLLOWING) ";
}
@Override
public OffsetFollowingEnd<A> copy() {
return new OffsetFollowingEnd<A>((FrameStart<A>) getStart().copy(), getOffset().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional() && getOffset().isPurelyFunctional();
}
}
public static class UnboundedFollowingEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public UnboundedFollowingEnd(FrameStart<A> aThis) {
super(aThis);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " AND UNBOUNDED FOLLOWING )";
}
@Override
public UnboundedFollowingEnd<A> copy() {
return new UnboundedFollowingEnd<A>((FrameStart<A>) getStart().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional();
}
}
public static class EmptyFrameEnd<A extends EqualExpression<?, ?, ?>> extends FrameEnd<A> {
public EmptyFrameEnd(WindowPart<A> aThis) {
super(aThis);
}
@Override
public String toSQLString(DBDefinition defn) {
return getStart().toSQLString(defn) + " )";
}
@Override
public EmptyFrameEnd<A> copy() {
return new EmptyFrameEnd<A>(getStart().copy());
}
@Override
public boolean isPurelyFunctional() {
return getStart().isPurelyFunctional();
}
}
}