Make Query.Property parameterised with <BT> "Base Type" as Number, String, Temporal, Boolean or Object

These types then determine which functions are valid for the types. So:
- Number functions
- String/varchar functions
- Temporal Date, DateTime, Time functions
- Boolean functions
- Object being everything else
This commit is contained in:
Rob Bygrave
2022-11-08 21:57:36 +13:00
parent 0b9d199829
commit 97bbce321d
43 changed files with 353 additions and 145 deletions
@@ -6,7 +6,7 @@ package io.ebean.typequery;
* @param <R> the root query bean type
* @param <E> the element type of the DbArray
*/
public final class PArray<R, E> extends TQPropertyBase<R> {
public final class PArray<R, E> extends TQPropertyBase<R, E> {
/**
* Construct with a property name and root instance.
@@ -6,11 +6,11 @@ import io.ebean.Query;
/**
* Base property for all comparable types.
*
* @param <R> the root query bean type
* @param <T> the type of the scalar property
* @param <R> the root query bean type
* @param <T> the type of the scalar property
* @param <BT> the base type of the property
*/
@SuppressWarnings("rawtypes")
public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
public abstract class PBaseCompareable<R, T, BT> extends PBaseValueEqual<R, T, BT> {
/**
* Construct with a property name and root instance.
@@ -44,11 +44,14 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
/**
* Greater than other property.
* <p>
* Note that the other property must have the same common "Base type" (String, Number, Temporal, Boolean or Object).
*
* @param other the other property to compare
*
* @return the root query bean instance
*/
public final R gt(TQProperty<?> other) {
public final R gt(TQProperty<?, BT> other) {
expr().raw(_name + " > " + other.propertyName());
return _root;
}
@@ -81,7 +84,7 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R ge(TQProperty<?> other) {
public final R ge(TQProperty<?, BT> other) {
expr().raw(_name + " >= " + other.propertyName());
return _root;
}
@@ -114,7 +117,7 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R lt(TQProperty<?> other) {
public final R lt(TQProperty<?, BT> other) {
expr().raw(_name + " < " + other.propertyName());
return _root;
}
@@ -147,7 +150,7 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R le(TQProperty<?> other) {
public final R le(TQProperty<?, BT> other) {
expr().raw(_name + " <= " + other.propertyName());
return _root;
}
@@ -197,7 +200,7 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* The most common use of this could be called "effective dating" where 2 date or
* timestamp columns represent the date range in which
*/
public final R inRangeWith(TQProperty<R> highProperty, T value) {
public final R inRangeWith(TQProperty<?, BT> highProperty, T value) {
expr().inRangeWith(_name, highProperty._name, value);
return _root;
}
@@ -220,7 +223,7 @@ public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
* <p>
* This is a convenience expression combining a number of simple expressions.
*/
public final R inRangeWith(TQProperty<?> lowProperty, TQProperty<?> highProperty) {
public final R inRangeWith(TQProperty<?, BT> lowProperty, TQProperty<?, BT> highProperty) {
expr().inRangeWithProperties(_name, lowProperty.propertyName(), highProperty.propertyName());
return _root;
}
@@ -1,5 +1,7 @@
package io.ebean.typequery;
import java.time.temporal.Temporal;
/**
* Base property for date and date time types.
*
@@ -7,7 +9,7 @@ package io.ebean.typequery;
* @param <D> the date time type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareable<R, D> {
public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareable<R, D, Temporal> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ package io.ebean.typequery;
* @param <T> the number type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseNumber<R,T extends Comparable> extends PBaseCompareable<R,T> {
public abstract class PBaseNumber<R, T extends Comparable> extends PBaseCompareable<R, T, Number> {
/**
* Construct with a property name and root instance.
@@ -16,7 +16,7 @@ public abstract class PBaseNumber<R,T extends Comparable> extends PBaseCompareab
* @param root the root query bean instance
*/
public PBaseNumber(String name, R root) {
super(name , root);
super(name, root);
}
/**
@@ -5,7 +5,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
public abstract class PBaseString<R, T> extends PBaseCompareable<R, T, String> {
/**
* Construct with a property name and root instance.
@@ -25,22 +25,28 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Deprecated migrate to eq().
* <p>
* Is equal to. The same as <code>eq</code> but uses the strong type as argument rather than String.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
public final R equalToType(T value) {
expr().eq(_name, value);
return _root;
}
/**
* Deprecated migrate to ne().
* <p>
* Is not equal to. The same as <code>ne</code> but uses the strong type as argument rather than String.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
@Deprecated
public final R notEqualToType(T value) {
expr().ne(_name, value);
return _root;
@@ -49,7 +55,146 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
// common string / expressions ------------
/**
* Case insensitive is equal to.
* Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R eq(String value) {
expr().eq(_name, value);
return _root;
}
/**
* Not equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ne(String value) {
expr().ne(_name, value);
return _root;
}
/**
* Greater than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R gt(String value) {
expr().gt(_name, value);
return _root;
}
/**
* Greater than OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R gtOrNull(String value) {
expr().gtOrNull(_name, value);
return _root;
}
/**
* Greater than or Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ge(String value) {
expr().ge(_name, value);
return _root;
}
/**
* Greater than or Equal to OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R geOrNull(String value) {
expr().geOrNull(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R lt(String value) {
expr().lt(_name, value);
return _root;
}
/**
* Less than OR Null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R ltOrNull(String value) {
expr().ltOrNull(_name, value);
return _root;
}
/**
* Less than or Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R le(String value) {
expr().le(_name, value);
return _root;
}
/**
* Less than or Equal to OR null.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R leOrNull(String value) {
expr().leOrNull(_name, value);
return _root;
}
/**
* Greater or equal to lower value and strictly less than upper value.
* <p>
* This is generally preferable over Between for date and datetime types
* as SQL Between is inclusive on the upper bound ({@code <= }) and generally
* we need the upper bound to be exclusive ({@code < }).
* </p>
*
* @param lower the lower bind value ({@code >= })
* @param upper the upper bind value ({@code < })
* @return the root query bean instance
*/
public final R inRange(String lower, String upper) {
expr().inRange(_name, lower, upper);
return _root;
}
/**
* Between lower and upper values.
*
* @param lower the lower bind value
* @param upper the upper bind value
* @return the root query bean instance
*/
public final R between(String lower, String upper) {
expr().between(_name, lower, upper);
return _root;
}
/**
* Case-insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -60,7 +205,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive is equal to.
* Case-insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -115,7 +260,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive like.
* Case-insensitive like.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -126,7 +271,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive starts with.
* Case-insensitive starts with.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -137,7 +282,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive ends with.
* Case-insensitive ends with.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -148,7 +293,7 @@ public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
}
/**
* Case insensitive contains.
* Case-insensitive contains.
*
* @param value the equal to bind value
* @return the root query bean instance
@@ -0,0 +1,52 @@
package io.ebean.typequery;
import java.time.temporal.Temporal;
/**
* Base property for time types.
*
* @param <R> the root query bean type
* @param <T> the number type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseTime<R, T extends Comparable> extends PBaseCompareable<R, T, Temporal> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBaseTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBaseTime(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Same as greater than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R after(T value) {
expr().gt(_name, value);
return _root;
}
/**
* Same as less than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R before(T value) {
expr().lt(_name, value);
return _root;
}
}
@@ -11,7 +11,7 @@ import java.util.Collection;
* @param <R> the root query bean type
* @param <T> the number type
*/
public abstract class PBaseValueEqual<R, T> extends TQPropertyBase<R> {
public abstract class PBaseValueEqual<R, T, BT> extends TQPropertyBase<R, BT> {
/**
* Construct with a property name and root instance.
@@ -89,7 +89,7 @@ public abstract class PBaseValueEqual<R, T> extends TQPropertyBase<R> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R eq(TQProperty<?> other) {
public final R eq(TQProperty<?, BT> other) {
expr().raw(_name + " = " + other.propertyName());
return _root;
}
@@ -152,7 +152,7 @@ public abstract class PBaseValueEqual<R, T> extends TQPropertyBase<R> {
* @param other the other property to compare
* @return the root query bean instance
*/
public final R ne(TQProperty<?> other) {
public final R ne(TQProperty<?, BT> other) {
expr().raw(_name + " <> " + other.propertyName());
return _root;
}
@@ -5,7 +5,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public final class PBoolean<R> extends PBaseValueEqual<R, Boolean> {
public final class PBoolean<R> extends PBaseValueEqual<R, Boolean, Boolean> {
/**
* Construct with a property name and root instance.
@@ -5,7 +5,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public final class PByteArray<R> extends PBaseValueEqual<R, byte[]> {
public final class PByteArray<R> extends PBaseValueEqual<R, byte[], Object> {
/**
* Construct with a property name and root instance.
@@ -24,5 +24,4 @@ public final class PByteArray<R> extends PBaseValueEqual<R, byte[]> {
super(name, root, prefix);
}
}
@@ -7,7 +7,7 @@ import io.ebean.types.Cidr;
*
* @param <R> the root query bean type
*/
public final class PCidr<R> extends PBaseValueEqual<R, Cidr> {
public final class PCidr<R> extends PBaseString<R, Cidr> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.util.Currency;
*
* @param <R> the root query bean type
*/
public final class PCurrency<R> extends PBaseValueEqual<R,Currency> {
public final class PCurrency<R> extends PBaseString<R, Currency> {
/**
* Construct with a property name and root instance.
@@ -1,12 +1,12 @@
package io.ebean.typequery;
/**
* BigDecimal property.
* Enum property.
*
* @param <E> the enum specific type
* @param <R> the root query bean type
*/
public final class PEnum<R,E> extends PBaseValueEqual<R,E> {
public final class PEnum<R, E> extends PBaseValueEqual<R, E, Object> {
/**
* Construct with a property name and root instance.
@@ -9,7 +9,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public final class PFile<R> extends TQPropertyBase<R> {
public final class PFile<R> extends TQPropertyBase<R, Object> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import io.ebean.types.Inet;
*
* @param <R> the root query bean type
*/
public final class PInet<R> extends PBaseValueEqual<R, Inet> {
public final class PInet<R> extends PBaseString<R, Inet> {
/**
* Construct with a property name and root instance.
@@ -7,8 +7,7 @@ import java.net.InetAddress;
*
* @param <R> the root query bean type
*/
public final class PInetAddress<R> extends PBaseValueEqual<R,InetAddress> {
public final class PInetAddress<R> extends PBaseString<R, InetAddress> {
/**
* Construct with a property name and root instance.
@@ -8,7 +8,7 @@ import org.joda.time.LocalTime;
*
* @param <R> the root query bean type
*/
public final class PJodaLocalTime<R> extends PBaseNumber<R,LocalTime> {
public final class PJodaLocalTime<R> extends PBaseTime<R, LocalTime> {
/**
* Construct with a property name and root instance.
@@ -17,7 +17,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public final class PJson<R> extends TQPropertyBase<R> {
public final class PJson<R> extends TQPropertyBase<R, String> {
/**
* Construct with a property name and root instance.
@@ -8,7 +8,7 @@ import java.time.LocalTime;
*
* @param <R> the root query bean type
*/
public final class PLocalTime<R> extends PBaseNumber<R,LocalTime> {
public final class PLocalTime<R> extends PBaseTime<R, LocalTime> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.time.OffsetDateTime;
*
* @param <R> the root query bean type
*/
public final class POffsetDateTime<R> extends PBaseNumber<R,OffsetDateTime> {
public final class POffsetDateTime<R> extends PBaseDate<R,OffsetDateTime> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.time.OffsetTime;
*
* @param <R> the root query bean type
*/
public final class POffsetTime<R> extends PBaseNumber<R,OffsetTime> {
public final class POffsetTime<R> extends PBaseTime<R, OffsetTime> {
/**
* Construct with a property name and root instance.
@@ -1,13 +1,12 @@
package io.ebean.typequery;
/**
* Property for classes that are serialized/deserialized by
* ScalarType/AttributeConverter.
* Property for classes that are serialized/deserialized by ScalarType/AttributeConverter.
*
* @param <R> the root query bean type
* @param <D> the scalar type
*/
public final class PScalar<R, D> extends PBaseValueEqual<R, D> {
public final class PScalar<R, D> extends PBaseValueEqual<R, D, Object> {
/**
* Construct with a property name and root instance.
@@ -8,7 +8,7 @@ package io.ebean.typequery;
* @param <R> the root query bean type
* @param <D> the scalar type
*/
public final class PScalarComparable<R, D extends Comparable<D>> extends PBaseCompareable<R, D> {
public final class PScalarComparable<R, D extends Comparable<D>> extends PBaseCompareable<R, D, Object> {
/**
* Construct with a property name and root instance.
@@ -5,7 +5,7 @@ package io.ebean.typequery;
*
* @param <R> the root query bean type
*/
public final class PString<R> extends PBaseCompareable<R, String> {
public final class PString<R> extends PBaseCompareable<R, String, String> {
/**
* Construct with a property name and root instance.
@@ -8,7 +8,7 @@ import java.sql.Time;
*
* @param <R> the root query bean type
*/
public final class PTime<R> extends PBaseNumber<R,Time> {
public final class PTime<R> extends PBaseTime<R,Time> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.util.TimeZone;
*
* @param <R> the root query bean type
*/
public final class PTimeZone<R> extends PBaseValueEqual<R,TimeZone> {
public final class PTimeZone<R> extends PBaseString<R, TimeZone> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.util.UUID;
*
* @param <R> the root query bean type
*/
public final class PUuid<R> extends PBaseValueEqual<R,UUID> {
public final class PUuid<R> extends PBaseValueEqual<R, UUID, Object> {
/**
* Construct with a property name and root instance.
@@ -16,7 +16,7 @@ public final class PUuid<R> extends PBaseValueEqual<R,UUID> {
* @param root the root query bean instance
*/
public PUuid(String name, R root) {
super(name , root);
super(name, root);
}
/**
@@ -7,7 +7,7 @@ import java.time.ZoneId;
*
* @param <R> the root query bean type
*/
public final class PZoneId<R> extends PBaseValueEqual<R,ZoneId> {
public final class PZoneId<R> extends PBaseString<R, ZoneId> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.time.ZoneOffset;
*
* @param <R> the root query bean type
*/
public final class PZoneOffset<R> extends PBaseValueEqual<R,ZoneOffset> {
public final class PZoneOffset<R> extends PBaseString<R, ZoneOffset> {
/**
* Construct with a property name and root instance.
@@ -7,7 +7,7 @@ import java.time.ZonedDateTime;
*
* @param <R> the root query bean type
*/
public final class PZonedDateTime<R> extends PBaseCompareable<R, ZonedDateTime> {
public final class PZonedDateTime<R> extends PBaseDate<R, ZonedDateTime> {
/**
* Construct with a property name and root instance.
@@ -26,25 +26,4 @@ public final class PZonedDateTime<R> extends PBaseCompareable<R, ZonedDateTime>
super(name, root, prefix);
}
/**
* Same as greater than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R after(ZonedDateTime value) {
expr().gt(_name, value);
return _root;
}
/**
* Same as less than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R before(ZonedDateTime value) {
expr().lt(_name, value);
return _root;
}
}
@@ -17,7 +17,7 @@ import java.util.Set;
* @param <R> the specific root query bean type (e.g. QCustomer)
*/
@SuppressWarnings("rawtypes")
public abstract class TQAssocBean<T, R> extends TQProperty<R> {
public abstract class TQAssocBean<T, R> extends TQProperty<R, Object> {
private static final FetchConfig FETCH_DEFAULT = FetchConfig.ofDefault();
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
@@ -111,7 +111,7 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R> {
* Eagerly fetch this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchProperties(TQProperty<?>... props) {
protected final R fetchProperties(TQProperty<?, ?>... props) {
return fetchWithProperties(FETCH_DEFAULT, props);
}
@@ -119,7 +119,7 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R> {
* Eagerly fetch query this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchQueryProperties(TQProperty<?>... props) {
protected final R fetchQueryProperties(TQProperty<?, ?>... props) {
return fetchWithProperties(FETCH_QUERY, props);
}
@@ -127,7 +127,7 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R> {
* Eagerly fetch this association using L2 bean cache.
*/
@SafeVarargs
protected final R fetchCacheProperties(TQProperty<?>... props) {
protected final R fetchCacheProperties(TQProperty<?, ?>... props) {
return fetchWithProperties(FETCH_CACHE, props);
}
@@ -135,12 +135,12 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R> {
* Eagerly fetch query this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchLazyProperties(TQProperty<?>... props) {
protected final R fetchLazyProperties(TQProperty<?, ?>... props) {
return fetchWithProperties(FETCH_LAZY, props);
}
@SafeVarargs
private R fetchWithProperties(FetchConfig config, TQProperty<?>... props) {
private R fetchWithProperties(FetchConfig config, TQProperty<?, ?>... props) {
spiQuery().fetchProperties(_name, properties(props), config);
return _root;
}
@@ -173,13 +173,13 @@ public abstract class TQAssocBean<T, R> extends TQProperty<R> {
}
private SpiQueryFetch spiQuery() {
return (SpiQueryFetch)((TQRootBean) _root).query();
return (SpiQueryFetch) ((TQRootBean) _root).query();
}
@SafeVarargs
private Set<String> properties(TQProperty<?>... props) {
private Set<String> properties(TQProperty<?, ?>... props) {
Set<String> set = new LinkedHashSet<>();
for (TQProperty<?> prop : props) {
for (TQProperty<?, ?> prop : props) {
set.add(prop.propertyName());
}
return set;
@@ -6,12 +6,12 @@ import io.ebean.Query;
/**
* A property used in type query.
*
* @param <R> The type of the owning root bean
* @param <R> The type of the owning root bean
* @param <BT> The base type, one of String, Number, Temporal, Boolean, Object.
*/
public class TQProperty<R> implements Query.Property {
public class TQProperty<R, BT> implements Query.Property<BT> {
protected final String _name;
protected final R _root;
/**
@@ -41,7 +41,7 @@ public class TQProperty<R> implements Query.Property {
* Internal method to return the underlying expression list.
*/
protected final ExpressionList<?> expr() {
return ((TQRootBean<?,?>) _root).peekExprList();
return ((TQRootBean<?, ?>) _root).peekExprList();
}
/**
@@ -3,9 +3,10 @@ package io.ebean.typequery;
/**
* Base scalar property.
*
* @param <R> The type of the owning root bean
* @param <R> The type of the owning root bean
* @param <BT> The base type of the property
*/
public class TQPropertyBase<R> extends TQProperty<R> {
public abstract class TQPropertyBase<R, BT> extends TQProperty<R, BT> {
/**
* Construct with a property name and root instance.
@@ -263,14 +263,14 @@ public abstract class TQRootBean<T, R> {
* @param properties the list of properties to fetch
*/
@SafeVarargs
public final R select(TQProperty<R>... properties) {
public final R select(TQProperty<R, ?>... properties) {
((SpiQueryFetch) query).selectProperties(properties(properties));
return root;
}
private Set<String> properties(Query.Property[] properties) {
private Set<String> properties(Query.Property<?>[] properties) {
Set<String> props = new LinkedHashSet<>();
for (Query.Property property : properties) {
for (Query.Property<?> property : properties) {
props.add(property.toString());
}
return props;