DBIntegerEnum.java
/*
* Copyright 2014 Gregory Graham.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nz.co.gregs.dbvolution.datatypes;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import nz.co.gregs.dbvolution.DBReport;
import nz.co.gregs.dbvolution.DBRow;
import nz.co.gregs.dbvolution.columns.IntegerColumn;
import nz.co.gregs.dbvolution.databases.definitions.DBDefinition;
import nz.co.gregs.dbvolution.exceptions.IncorrectRowProviderInstanceSuppliedException;
import nz.co.gregs.dbvolution.expressions.IntegerExpression;
import nz.co.gregs.dbvolution.expressions.StringExpression;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeExclusiveOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeInclusiveOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedRangeOperator;
import nz.co.gregs.dbvolution.operators.DBPermittedValuesOperator;
import nz.co.gregs.dbvolution.query.RowDefinition;
import nz.co.gregs.dbvolution.results.IntegerResult;
import nz.co.gregs.dbvolution.utility.comparators.ComparableComparator;
/**
* Like {@link DBInteger} except that the database value can be easily
* interpreted as an enumeration with {@code Integer} or {@code Long} codes.
*
* <p>
* Normally declared as something like:</p>
* <pre>
* {@literal @}DBColumn
* DBintegerEnum state = new DBIntegerEnum<MyEnumValue>();
*
*
* public static enum MyEnumValue implements DBEnumValue<Integer> {
*
* STATE_ONE(1, "One"),
* STATE_TWO(2, "Two"),
* STATE_THREE(3, "Three");
* private final Integer literalValue;
* private final String displayName;
*
* private GenericEnumType(Integer code, String displayName) {
* this.literalValue = code;
* this.displayName = displayName;
* }
*
* public Integer getCode() {
* return literalValue;
* }
*
* public String getDisplayName() {
* return displayName;
* }
* }
* </pre>
*
*
*
* @param <E> type of enumeration class
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
* @author Malcolm Lett
* @author Gregory Graham
*/
public class DBIntegerEnum<E extends Enum<E> & DBEnumValue<Long>> extends DBEnum<E, Long> implements IntegerResult {
private static final long serialVersionUID = 1L;
/**
* The default constructor for DBIntegerEnum.
*
* <p>
* Creates an unset undefined DBIntegerEnum object.
*
*/
public DBIntegerEnum() {
}
/**
* Creates a DBIntegerEnum set to the value supplied.
*
* @param value value
*/
public DBIntegerEnum(Integer value) {
super(value.longValue());
}
/**
* Creates a DBIntegerEnum set to the value supplied..
*
* @param value value
*/
public DBIntegerEnum(Long value) {
super(value);
}
/**
* Creates a DBIntegerEnum that will be evaluated on the database using the
* expression supplied.
*
* <p>
* This constructor is used in {@link DBReport DBReports} to generate new
* information from existing data using the databases builtin capabilities.
*
* @param numberExpression numberExpression
*/
public DBIntegerEnum(IntegerExpression numberExpression) {
super(numberExpression);
}
/**
* Creates a DBIntegerEnum set to the value supplied..
*
* @param value value
*/
public DBIntegerEnum(E value) {
super(value);
}
@Override
protected void validateLiteralValue(E enumValue) {
Object code = enumValue.getCode();
if (code != null) {
if (!(code instanceof Integer || code instanceof Long)) {
String enumMethodRef = enumValue.getClass().getName() + "." + enumValue.name() + ".getLiteralValue()";
String literalValueTypeRef = code.getClass().getName();
throw new IncompatibleClassChangeError("Enum literal type is not valid: "
+ enumMethodRef + " returned a " + literalValueTypeRef + ", which is not valid for a " + this.getClass().getSimpleName());
}
}
}
@Override
public String getSQLDatatype() {
return new DBInteger().getSQLDatatype();
}
@Override
public DBInteger getQueryableDatatypeForExpressionValue() {
return new DBInteger();
}
@Override
public boolean isAggregator() {
return false;
}
@Override
public Set<DBRow> getTablesInvolved() {
return new HashSet<DBRow>();
}
@SafeVarargs
@SuppressWarnings("unchecked")
@Override
protected final Long[] convertToLiteral(E... enumValues) {
return convertToLiteralLong(enumValues);
}
/**
* Create an array of Longs containing the literal values of the provided
* Enums.
*
* <p>
* Provided as a convenience function
*
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @param enumValues the values to transform into Longs
* @return a Long[] of the enums values.
*/
@SafeVarargs
protected final Long[] convertToLiteralLong(E... enumValues) {
Long[] result = new Long[enumValues.length];
for (int i = 0; i < enumValues.length; i++) {
E enumValue = enumValues[i];
result[i] = convertToLiteralLong(enumValue);
}
return result;
}
/**
* Convert the enum to its Long literal value.
*
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return the literal value of the enum.
*/
private Long convertToLiteralLong(E enumValue) {
if (enumValue == null || enumValue.getCode() == null) {
return null;
} else {
validateLiteralValue(enumValue);
Long newLiteralValue = enumValue.getCode();
return newLiteralValue;
}
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e permittedRange(1,3) will
* return 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRange(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRange(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRange(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeOperator<Long>(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e permittedRangeInclusive(1,3) will
* return 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(null, 5) will return 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeInclusive(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e permittedRangeExclusive(1,3) will
* return 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(1,null) will return 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeExclusive(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e excludedRange(1,3) will
* exclude 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRange(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRange(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRange(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeOperator<Long>(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e excludedRangeInclusive(1,3) will
* exclude 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(null, 5) will exclude 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeInclusive(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e excludedRangeExclusive(1,3) will
* exclude 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(1,null) will exclude 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeExclusive(E lowerBound, E upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(convertToLiteral(lowerBound), convertToLiteral(upperBound)));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e permittedRange(1,3) will
* return 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRange(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRange(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRange(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeOperator<Long>(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e permittedRangeInclusive(1,3) will
* return 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(null, 5) will return 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeInclusive(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e permittedRangeExclusive(1,3) will
* return 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(1,null) will return 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeExclusive(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e excludedRange(1,3) will
* exclude 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRange(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRange(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRange(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeOperator<Long>(lowerBound, upperBound));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e excludedRangeInclusive(1,3) will
* exclude 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(null, 5) will exclude 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeInclusive(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e excludedRangeExclusive(1,3) will
* exclude 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(1,null) will exclude 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeExclusive(Long lowerBound, Long upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
negateOperator();
}
/**
*
* reduces the rows to only the object, Set, List, Array, or vararg of objects
*
* @param permitted permitted
*/
public void permittedValues(Integer... permitted) {
this.setOperator(new DBPermittedValuesOperator<Integer>(permitted));
}
/**
*
* excludes the object, Set, List, Array, or vararg of objects
*
*
* @param excluded excluded
*/
public void excludedValues(Integer... excluded) {
this.setOperator(new DBPermittedValuesOperator<Integer>(excluded));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e permittedRange(1,3) will
* return 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRange(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRange(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRange(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeOperator<Integer>(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e permittedRangeInclusive(1,3) will
* return 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(1,null) will return 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e permittedRangeInclusive(null, 5) will return 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeInclusive(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e permittedRangeExclusive(1,3) will
* return 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(1,null) will return 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e permittedRangeExclusive(null, 5) will return 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void permittedRangeExclusive(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified the lower-bound will be included in
* the search and the upper-bound excluded. I.e excludedRange(1,3) will
* exclude 1 and 2.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRange(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRange(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRange(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeOperator<Integer>(lowerBound, upperBound));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be included in the search. I.e excludedRangeInclusive(1,3) will
* exclude 1, 2, and 3.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(1,null) will exclude 1,2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and inclusive.
* <br>
* I.e excludedRangeInclusive(null, 5) will exclude 5,4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeInclusive(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeInclusiveOperator(lowerBound, upperBound));
negateOperator();
}
/**
* Performs searches based on a range.
*
* if both ends of the range are specified both the lower- and upper-bound
* will be excluded in the search. I.e excludedRangeExclusive(1,3) will
* exclude 2.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(1,null) will exclude 2,3,4,5, etc.
*
* <p>
* if the upper-bound is null the range will be open ended and exclusive.
* <br>
* I.e excludedRangeExclusive(null, 5) will exclude 4,3,2,1, etc.
*
* @param lowerBound lowerBound
* @param upperBound upperBound
*/
public void excludedRangeExclusive(Integer lowerBound, Integer upperBound) {
setOperator(new DBPermittedRangeExclusiveOperator(lowerBound, upperBound));
negateOperator();
}
/**
* Returns the set value of this DBInteger as a Number, if possible.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return the value as a Number.
*/
public Long numberValue() {
if (getLiteralValue() == null) {
return null;
} else if (getLiteralValue() instanceof Number) {
return getLiteralValue();
} else {
return Long.parseLong(getLiteralValue().toString());
}
}
/**
* Returns the set value of this DBInteger as a Long, if possible.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return the value as a Long.
*/
public Long longValue() {
if (getLiteralValue() == null) {
return null;
} else {
return getLiteralValue();
}
}
/**
* Returns the set value of this DBInteger as a Integer, if possible.
*
* <p style="color: #F90;">Support DBvolution at
* <a href="http://patreon.com/dbvolution" target=new>Patreon</a></p>
*
* @return the value as a Integer.
*/
public Integer intValue() {
if (getLiteralValue() == null) {
return null;
} else {
return Integer.parseInt(getLiteralValue().toString());
}
}
@Override
public Long getValue() {
return numberValue();
}
@Override
protected Long getFromResultSet(DBDefinition database, ResultSet resultSet, String fullColumnName) throws SQLException {
return resultSet.getLong(fullColumnName);
}
@Override
@SuppressWarnings("unchecked")
public DBIntegerEnum<E> copy() {
return (DBIntegerEnum<E>) super.copy();
}
@Override
public boolean getIncludesNull() {
return isNull();
}
@Override
public StringExpression stringResult() {
return StringExpression.value("" + getValue());
}
@Override
public boolean isPurelyFunctional() {
return false;
}
@Override
protected void setValueFromStandardStringEncoding(String encodedValue) {
if (encodedValue.isEmpty()) {
super.setLiteralValue(null);
} else {
try {
Double parseDouble = Double.parseDouble(encodedValue);
Long literalLong = parseDouble.longValue();
setLiteralValue(literalLong);
} catch (NumberFormatException noFormat) {
setLiteralValue(null);
}
}
}
@Override
public IntegerColumn getColumn(RowDefinition row) throws IncorrectRowProviderInstanceSuppliedException {
return new IntegerColumn(row, this);
}
@Override
public Comparator<Long> getComparator() {
return ComparableComparator.forClass(Long.class);
}
}