#2069 - Add ebean-querybean, querybean-generator and kotlin-querybean-generator as modules

This commit is contained in:
rob bygrave
2020-10-09 00:02:09 +13:00
parent bc055fea25
commit 038db79737
140 changed files with 11583 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# ebean-querybean
Type safe query extension for Ebean ORM
Refer to the documentation at https://ebean.io/docs/query/query-beans
+92
View File
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.4.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ebean-querybean</artifactId>
<dependencies>
<!-- provided scope for now -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<!--
Class retention Nonnull and Nullable annotations
to assist with IDE auto-completion with Ebean API
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsr305</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>1.6</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>junit</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>logback</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Enhancement -->
<plugin>
<groupId>io.repaint.maven</groupId>
<artifactId>tiles-maven-plugin</artifactId>
<version>2.17</version>
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:12.4.2</tile>
</tiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,18 @@
package io.ebean.typequery;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to denote a query bean that has already been enhanced.
* <p>
* Used by the agent to detect already enhanced type query beans to skip enhancement processing.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface AlreadyEnhancedMarker {
}
@@ -0,0 +1,98 @@
package io.ebean.typequery;
/**
* Array property with E as the element type.
*
* @param <R> the root query bean type
* @param <E> the element type of the DbArray
*/
public class PArray<R, E> extends TQPropertyBase<R> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PArray(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PArray(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* ARRAY contains the values.
* <p>
* <pre>{@code
*
* new QContact()
* .phoneNumbers.contains("4321")
* .findList();
*
* }</pre>
*
* @param values The values that should be contained in the array
*/
@SafeVarargs
public final R contains(E... values) {
expr().arrayContains(_name, (Object[]) values);
return _root;
}
/**
* ARRAY does not contain the values.
* <p>
* <pre>{@code
*
* new QContact()
* .phoneNumbers.notContains("4321")
* .findList();
*
* }</pre>
*
* @param values The values that should not be contained in the array
*/
@SafeVarargs
public final R notContains(E... values) {
expr().arrayNotContains(_name, (Object[]) values);
return _root;
}
/**
* ARRAY is empty.
* <p>
* <pre>{@code
*
* new QContact()
* .phoneNumbers.isEmpty()
* .findList();
*
* }</pre>
*/
public R isEmpty() {
expr().arrayIsEmpty(_name);
return _root;
}
/**
* ARRAY is not empty.
* <p>
* <pre>{@code
*
* new QContact()
* .phoneNumbers.isNotEmpty()
* .findList();
*
* }</pre>
*/
public R isNotEmpty() {
expr().arrayIsNotEmpty(_name);
return _root;
}
}
@@ -0,0 +1,237 @@
package io.ebean.typequery;
/**
* Base property for all comparable types.
*
* @param <R> the root query bean type
* @param <T> the type of the scalar property
*/
@SuppressWarnings("rawtypes")
public class PBaseCompareable<R, T> extends PBaseValueEqual<R, T> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBaseCompareable(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBaseCompareable(String name, R root, String prefix) {
super(name, root, prefix);
}
// ---- range comparisons -------
/**
* Greater than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R gt(T 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(T 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(T 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(T value) {
expr().geOrNull(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R lt(T 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(T 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(T value) {
expr().le(_name, value);
return _root;
}
/**
* Less than or Equal to.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R leOrNull(T 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 (<=) and generally we
* need the upper bound to be exclusive (<).
* </p>
*
* @param lower the lower bind value (>=)
* @param upper the upper bind value (<)
* @return the root query bean instance
*/
public final R inRange(T lower, T upper) {
expr().inRange(_name, lower, upper);
return _root;
}
/**
* Value in Range between 2 properties.
*
* <pre>{@code
*
* .startDate.inRangeWith(endDate, now)
*
* // which equates to
* startDate <= now and (endDate > now or endDate is null)
*
* }</pre>
*
* <p>
* This is a convenience expression combining a number of simple expressions.
* 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) {
expr().inRangeWith(_name, highProperty._name, value);
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(T lower, T upper) {
expr().between(_name, lower, upper);
return _root;
}
/**
* Greater than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R greaterThan(T 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 greaterThanOrNull(T 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 greaterOrEqualTo(T value) {
expr().ge(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the bind value
* @return the root query bean instance
*/
public final R lessThan(T 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 lessThanOrNull(T 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 lessOrEqualTo(T value) {
expr().le(_name, value);
return _root;
}
}
@@ -0,0 +1,50 @@
package io.ebean.typequery;
/**
* Base property for date and date time types.
*
* @param <R> the root query bean type
* @param <D> the date time type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseDate<R, D extends Comparable> extends PBaseCompareable<R, D> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBaseDate(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PBaseDate(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 R after(D 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(D value) {
expr().lt(_name, value);
return _root;
}
}
@@ -0,0 +1,109 @@
package io.ebean.typequery;
/**
* Base property for number types.
*
* @param <R> the root query bean type
* @param <T> the number type
*/
@SuppressWarnings("rawtypes")
public abstract class PBaseNumber<R,T extends Comparable> extends PBaseCompareable<R,T> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBaseNumber(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PBaseNumber(String name, R root, String prefix) {
super(name, root, prefix);
}
// Additional int versions -- seems the right thing to do
/**
* Is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R equalTo(int value) {
expr().eq(_name, value);
return _root;
}
/**
* Greater than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R greaterThan(int value) {
expr().gt(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R lessThan(int value) {
expr().lt(_name, value);
return _root;
}
/**
* Is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R eq(int value) {
expr().eq(_name, value);
return _root;
}
/**
* Greater than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R gt(int value) {
expr().gt(_name, value);
return _root;
}
/**
* Less than.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R lt(int value) {
expr().lt(_name, value);
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 R between(int lower, int upper) {
expr().between(_name, lower, upper);
return _root;
}
}
@@ -0,0 +1,173 @@
package io.ebean.typequery;
/**
* Base for property types that store as String Varchar types.
*
* @param <R> the root query bean type
*/
public abstract class PBaseString<R,T> extends PBaseCompareable<R, String> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
PBaseString(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
PBaseString(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* 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
*/
public final R equalToType(T value) {
expr().eq(_name, value);
return _root;
}
/**
* 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
*/
public final R notEqualToType(T value) {
expr().ne(_name, value);
return _root;
}
// common string / expressions ------------
/**
* Case insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R ieq(String value) {
expr().ieq(_name, value);
return _root;
}
/**
* Case insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R iequalTo(String value) {
expr().ieq(_name, value);
return _root;
}
/**
* Like - include '%' and '_' placeholders as necessary.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R like(String value) {
expr().like(_name, value);
return _root;
}
/**
* Starts with - uses a like with '%' wildcard added to the end.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R startsWith(String value) {
expr().startsWith(_name, value);
return _root;
}
/**
* Ends with - uses a like with '%' wildcard added to the beginning.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R endsWith(String value) {
expr().endsWith(_name, value);
return _root;
}
/**
* Contains - uses a like with '%' wildcard added to the beginning and end.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R contains(String value) {
expr().contains(_name, value);
return _root;
}
/**
* Case insensitive like.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R ilike(String value) {
expr().ilike(_name, value);
return _root;
}
/**
* Case insensitive starts with.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R istartsWith(String value) {
expr().istartsWith(_name, value);
return _root;
}
/**
* Case insensitive ends with.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R iendsWith(String value) {
expr().iendsWith(_name, value);
return _root;
}
/**
* Case insensitive contains.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R icontains(String value) {
expr().icontains(_name, value);
return _root;
}
/**
* Add a full text "Match" expression.
* <p>
* This means the query will automatically execute against the document store (ElasticSearch).
* </p>
*
* @param value the match expression
*/
public R match(String value) {
expr().match(_name, value);
return _root;
}
}
@@ -0,0 +1,227 @@
package io.ebean.typequery;
import java.util.Collection;
/**
* Base property for types that primarily have equal to.
*
* @param <R> the root query bean type
* @param <T> the number type
*/
public abstract class PBaseValueEqual<R, T> extends TQPropertyBase<R> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBaseValueEqual(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBaseValueEqual(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Set the property as the map key for a <code>findMap</code> query.
*
* <pre>{@code
*
* Map<String, Customer> map =
* new QCustomer()
* .organisation.id.equalTo(42)
* .email.asMapKey() // email property as map key
* .findMap();
*
* }</pre>
*
* @return the root query bean instance
*/
public final R asMapKey() {
expr().setMapKey(_name);
return _root;
}
/**
* Is equal to or Null.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R equalToOrNull(T value) {
expr().eqOrNull(_name, value);
return _root;
}
/**
* Is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R equalTo(T value) {
expr().eq(_name, value);
return _root;
}
/**
* Is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R eq(T value) {
expr().eq(_name, value);
return _root;
}
/**
* Is equal to or Null.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R eqOrNull(T value) {
expr().eqOrNull(_name, value);
return _root;
}
/**
* Is not equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R notEqualTo(T value) {
expr().ne(_name, value);
return _root;
}
/**
* Is not equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public final R ne(T value) {
expr().ne(_name, value);
return _root;
}
/**
* Is in a list of values.
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
@SafeVarargs
public final R in(T... values) {
expr().in(_name, (Object[]) values);
return _root;
}
/**
* In where null or empty values means that no predicate is added to the query.
* <p>
* That is, only add the IN predicate if the values are not null or empty.
* <p>
* Without this we typically need to code an <code>if</code> block to only add
* the IN predicate if the collection is not empty like:
* </p>
*
* <h3>Without inOrEmpty()</h3>
* <pre>{@code
*
* List<String> names = Arrays.asList("foo", "bar");
*
* QCustomer query = new QCustomer()
* .registered.before(LocalDate.now())
*
* // conditionally add the IN expression to the query
* if (names != null && !names.isEmpty()) {
* query.name.in(names)
* }
*
* query.findList();
*
* }</pre>
*
* <h3>Using inOrEmpty()</h3>
* <pre>{@code
*
* List<String> names = Arrays.asList("foo", "bar");
*
* new QCustomer()
* .registered.before(LocalDate.now())
* .name.inOrEmpty(names)
* .findList();
*
* }</pre>
*/
public final R inOrEmpty(Collection<T> values) {
expr().inOrEmpty(_name, values);
return _root;
}
/**
* Is NOT in a list of values.
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
@SafeVarargs
public final R notIn(T... values) {
expr().notIn(_name, (Object[]) values);
return _root;
}
/**
* Is in a list of values. Synonym for in().
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
@SafeVarargs
public final R isIn(T... values) {
expr().in(_name, (Object[]) values);
return _root;
}
/**
* Is in a list of values.
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
public final R in(Collection<T> values) {
expr().in(_name, values);
return _root;
}
/**
* Is NOT in a list of values.
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
public final R notIn(Collection<T> values) {
expr().notIn(_name, values);
return _root;
}
/**
* Is in a list of values. Synonym for in().
*
* @param values the list of values for the predicate
* @return the root query bean instance
*/
public final R isIn(Collection<T> values) {
expr().in(_name, values);
return _root;
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.math.BigDecimal;
/**
* BigDecimal property.
* @param <R> the root query bean type
*/
public class PBigDecimal<R> extends PBaseNumber<R,BigDecimal> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBigDecimal(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBigDecimal(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.math.BigInteger;
/**
* BigInteger property.
*
* @param <R> the root query bean type
*/
public class PBigInteger<R> extends PBaseNumber<R, BigInteger> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBigInteger(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBigInteger(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,70 @@
package io.ebean.typequery;
/**
* Boolean property.
*
* @param <R> the root query bean type
*/
public class PBoolean<R> extends PBaseValueEqual<R, Boolean> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PBoolean(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PBoolean(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Is true.
*
* @return the root query bean instance
*/
public R isTrue() {
expr().eq(_name, Boolean.TRUE);
return _root;
}
/**
* Is false.
*
* @return the root query bean instance
*/
public R isFalse() {
expr().eq(_name, Boolean.FALSE);
return _root;
}
/**
* Is true or false based on the bind value.
*
* @param value the equal to bind value
*
* @return the root query bean instance
*/
public R is(boolean value) {
expr().eq(_name, value);
return _root;
}
/**
* Is true or false based on the bind value.
*
* @param value the equal to bind value
*
* @return the root query bean instance
*/
public R eq(boolean value) {
expr().eq(_name, value);
return _root;
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.util.Calendar;
/**
* Calendar property.
*
* @param <R> the root query bean type
*/
public class PCalendar<R> extends PBaseDate<R,Calendar> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PCalendar(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PCalendar(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import io.ebean.types.Cidr;
/**
* Cidr property.
*
* @param <R> the root query bean type
*/
public class PCidr<R> extends PBaseValueEqual<R, Cidr> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PCidr(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PCidr(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Class property.
*
* @param <R> the root query bean type
*/
public class PClass<R> extends PBaseString<R,Class> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PClass(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PClass(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.util.Currency;
/**
* Currency property.
*
* @param <R> the root query bean type
*/
public class PCurrency<R> extends PBaseValueEqual<R,Currency> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PCurrency(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PCurrency(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import java.time.DayOfWeek;
/**
* DayOfWeek property.
*
* @param <R> the root query bean type
*/
public class PDayOfWeek<R> extends PBaseNumber<R,DayOfWeek> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PDayOfWeek(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PDayOfWeek(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Double property.
*
* @param <R> the root query bean type
*/
public class PDouble<R> extends PBaseNumber<R,Double> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PDouble(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PDouble(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import java.time.Duration;
/**
* Duration property.
*
* @param <R> the root query bean type
*/
public class PDuration<R> extends PBaseNumber<R,Duration> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PDuration(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PDuration(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
/**
* BigDecimal property.
*
* @param <E> the enum specific type
* @param <R> the root query bean type
*/
public class PEnum<R,E> extends PBaseValueEqual<R,E> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PEnum(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PEnum(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,31 @@
package io.ebean.typequery;
/**
* File property.
* <p>
* This is a placeholder in the sense that currently it has no supported expressions.
* </p>
*
* @param <R> the root query bean type
*/
public class PFile<R> extends TQPropertyBase<R> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PFile(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PFile(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Float property.
*
* @param <R> the root query bean type
*/
public class PFloat<R> extends PBaseNumber<R,Float> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PFloat(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PFloat(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import io.ebean.types.Inet;
/**
* Inet property.
*
* @param <R> the root query bean type
*/
public class PInet<R> extends PBaseValueEqual<R, Inet> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PInet(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PInet(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.net.InetAddress;
/**
* InetAddress property.
*
* @param <R> the root query bean type
*/
public class PInetAddress<R> extends PBaseValueEqual<R,InetAddress> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PInetAddress(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PInetAddress(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import java.time.Instant;
/**
* Instant property.
*
* @param <R> the root query bean type
*/
public class PInstant<R> extends PBaseDate<R,Instant> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PInstant(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PInstant(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Integer property.
*
* @param <R> the root query bean type
*/
public class PInteger<R> extends PBaseNumber<R,Integer> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PInteger(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PInteger(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import org.joda.time.DateMidnight;
/**
* Joda DateMidnight property.
*
* @param <R> the root query bean type
*/
public class PJodaDateMidnight<R> extends PBaseDate<R,DateMidnight> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJodaDateMidnight(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJodaDateMidnight(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import org.joda.time.DateTime;
/**
* Joda DateTime property.
*
* @param <R> the root query bean type
*/
public class PJodaDateTime<R> extends PBaseDate<R,DateTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJodaDateTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJodaDateTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import org.joda.time.LocalDate;
/**
* Joda LocalDate property.
*
* @param <R> the root query bean type
*/
public class PJodaLocalDate<R> extends PBaseDate<R,LocalDate> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJodaLocalDate(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJodaLocalDate(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import org.joda.time.LocalDateTime;
/**
* Joda LocalDateTime property.
*
* @param <R> the root query bean type
*/
public class PJodaLocalDateTime<R> extends PBaseDate<R,LocalDateTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJodaLocalDateTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJodaLocalDateTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import org.joda.time.LocalTime;
/**
* Joda LocalTime property.
*
* @param <R> the root query bean type
*/
public class PJodaLocalTime<R> extends PBaseNumber<R,LocalTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJodaLocalTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJodaLocalTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,157 @@
package io.ebean.typequery;
/**
* JSON document type.
* <p>
* Type that is JSON content mapped to database types such as Postgres JSON/JSONB and otherwise Varchar,Clob and Blob.
* </p>
* <p>
* The expressions on this type are valid of Postgres and Oracle.
* </p>
*
* <p>
* The path can reference a nested property in the JSON document using dot notation -
* for example "documentMeta.score" where "score" is an embedded attribute of "documentMeta"
* </p>
*
* @param <R> the root query bean type
*/
public class PJson<R> extends TQPropertyBase<R> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PJson(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PJson(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Path exists - for the given path in a JSON document.
*
* <pre>{@code
*
* new QSimpleDoc()
* .content.jsonExists("meta.title")
* .findList();
*
* }</pre>
*
* @param path the nested path in the JSON document in dot notation
*/
public R jsonExists(String path) {
expr().jsonExists(_name, path);
return _root;
}
/**
* Path does not exist - for the given path in a JSON document.
*
* <pre>{@code
*
* new QSimpleDoc()
* .content.jsonNotExists("meta.title")
* .findList();
*
* }</pre>
*
* @param path the nested path in the JSON document in dot notation
*/
public R jsonNotExists(String path) {
expr().jsonNotExists(_name, path);
return _root;
}
/**
* Value at the given JSON path is equal to the given value.
*
*
* <pre>{@code
*
* new QSimpleDoc()
* .content.jsonEqualTo("title", "Rob JSON in the DB")
* .findList();
*
* }</pre>
*
* <pre>{@code
*
* new QSimpleDoc()
* .content.jsonEqualTo("path.other", 34)
* .findList();
*
* }</pre>
*
* @param path the dot notation path in the JSON document
* @param value the equal to bind value
*/
public R jsonEqualTo(String path, Object value) {
expr().jsonEqualTo(_name, path, value);
return _root;
}
/**
* Not Equal to - for the given path in a JSON document.
*
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test equality against the document path's value
*/
public R jsonNotEqualTo(String path, Object value) {
expr().jsonNotEqualTo(_name, path, value);
return _root;
}
/**
* Greater than - for the given path in a JSON document.
*
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
public R jsonGreaterThan(String path, Object value) {
expr().jsonGreaterThan(_name, path, value);
return _root;
}
/**
* Greater than or equal to - for the given path in a JSON document.
*
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
public R jsonGreaterOrEqual(String path, Object value) {
expr().jsonGreaterOrEqual(_name, path, value);
return _root;
}
/**
* Less than - for the given path in a JSON document.
*
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
public R jsonLessThan(String path, Object value) {
expr().jsonLessThan(_name, path, value);
return _root;
}
/**
* Less than or equal to - for the given path in a JSON document.
*
* @param path the nested path in the JSON document in dot notation
* @param value the value used to test against the document path's value
*/
public R jsonLessOrEqualTo(String path, Object value) {
expr().jsonLessOrEqualTo(_name, path, value);
return _root;
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.LocalDate;
/**
* LocalDate property.
*
* @param <R> the root query bean type
*/
public class PLocalDate<R> extends PBaseDate<R,LocalDate> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PLocalDate(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PLocalDate(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.LocalDateTime;
/**
* LocalDateTime property.
*
* @param <R> the root query bean type
*/
public class PLocalDateTime<R> extends PBaseDate<R,LocalDateTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PLocalDateTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PLocalDateTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import java.time.LocalTime;
/**
* LocalTime property.
*
* @param <R> the root query bean type
*/
public class PLocalTime<R> extends PBaseNumber<R,LocalTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PLocalTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PLocalTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.util.Locale;
/**
* Locale property.
*
* @param <R> the root query bean type
*/
public class PLocale<R> extends PBaseString<R, Locale> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PLocale(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PLocale(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Long property.
*
* @param <R> the root query bean type
*/
public class PLong<R> extends PBaseNumber<R,Long> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PLong(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PLong(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.Month;
/**
* LocalDateTime property.
*
* @param <R> the root query bean type
*/
public class PMonth<R> extends PBaseDate<R,Month> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PMonth(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PMonth(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.MonthDay;
/**
* MonthDay property.
*
* @param <R> the root query bean type
*/
public class PMonthDay<R> extends PBaseDate<R,MonthDay> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PMonthDay(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PMonthDay(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.time.OffsetDateTime;
/**
* OffsetDateTime property.
*
* @param <R> the root query bean type
*/
public class POffsetDateTime<R> extends PBaseNumber<R,OffsetDateTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public POffsetDateTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public POffsetDateTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.time.OffsetTime;
/**
* OffsetTime property.
*
* @param <R> the root query bean type
*/
public class POffsetTime<R> extends PBaseNumber<R,OffsetTime> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public POffsetTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public POffsetTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
/**
* Property for classes that are serialized/deserialized by
* ScalarType/AttributeConverter.
*
* @param <R> the root query bean type
* @param <D> the scalar type
*/
public class PScalar<R, D> extends PBaseValueEqual<R, D> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PScalar(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PScalar(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
/**
* Property for classes that are serialized/deserialized by
* ScalarType/AttributeConverter. If the classes are comparable,
* it is assumed that the database can compare the serialized values too.
*
* @param <R> the root query bean type
* @param <D> the scalar type
*/
public class PScalarComparable<R, D extends Comparable<D>> extends PBaseCompareable<R, D> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PScalarComparable(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PScalarComparable(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,27 @@
package io.ebean.typequery;
/**
* Short property.
*
* @param <R> the root query bean type
*/
public class PShort<R> extends PBaseNumber<R,Short> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PShort(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PShort(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.sql.Date;
/**
* Java sql Date property.
*
* @param <R> the root query bean type
*/
public class PSqlDate<R> extends PBaseDate<R,Date> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PSqlDate(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PSqlDate(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,149 @@
package io.ebean.typequery;
/**
* String property.
*
* @param <R> the root query bean type
*/
public class PString<R> extends PBaseCompareable<R, String> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PString(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PString(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Case insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R ieq(String value) {
expr().ieq(_name, value);
return _root;
}
/**
* Case insensitive is equal to.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R iequalTo(String value) {
expr().ieq(_name, value);
return _root;
}
/**
* Like - include '%' and '_' placeholders as necessary.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R like(String value) {
expr().like(_name, value);
return _root;
}
/**
* Starts with - uses a like with '%' wildcard added to the end.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R startsWith(String value) {
expr().startsWith(_name, value);
return _root;
}
/**
* Ends with - uses a like with '%' wildcard added to the beginning.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R endsWith(String value) {
expr().endsWith(_name, value);
return _root;
}
/**
* Contains - uses a like with '%' wildcard added to the beginning and end.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R contains(String value) {
expr().contains(_name, value);
return _root;
}
/**
* Case insensitive like.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R ilike(String value) {
expr().ilike(_name, value);
return _root;
}
/**
* Case insensitive starts with.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R istartsWith(String value) {
expr().istartsWith(_name, value);
return _root;
}
/**
* Case insensitive ends with.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R iendsWith(String value) {
expr().iendsWith(_name, value);
return _root;
}
/**
* Case insensitive contains.
*
* @param value the equal to bind value
* @return the root query bean instance
*/
public R icontains(String value) {
expr().icontains(_name, value);
return _root;
}
/**
* Add a full text "Match" expression.
* <p>
* This means the query will automatically execute against the document store (ElasticSearch).
* </p>
*
* @param value the match expression
*/
public R match(String value) {
expr().match(_name, value);
return _root;
}
}
@@ -0,0 +1,30 @@
package io.ebean.typequery;
import java.sql.Time;
/**
* Time property.
*
* @param <R> the root query bean type
*/
public class PTime<R> extends PBaseNumber<R,Time> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PTime(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PTime(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.util.TimeZone;
/**
* TimeZone property.
*
* @param <R> the root query bean type
*/
public class PTimeZone<R> extends PBaseValueEqual<R,TimeZone> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PTimeZone(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PTimeZone(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.sql.Timestamp;
/**
* Property for java sql Timestamp.
*
* @param <R> the root query bean type
*/
public class PTimestamp<R> extends PBaseDate<R,Timestamp> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PTimestamp(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PTimestamp(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.net.URI;
/**
* URI property.
*
* @param <R> the root query bean type
*/
public class PUri<R> extends PBaseString<R,URI> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PUri(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PUri(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.net.URL;
/**
* URL property.
*
* @param <R> the root query bean type
*/
public class PUrl<R> extends PBaseString<R,URL> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PUrl(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PUrl(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.util.Date;
/**
* Java util Date property.
*
* @param <R> the root query bean type
*/
public class PUtilDate<R> extends PBaseDate<R,Date> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PUtilDate(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PUtilDate(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.util.UUID;
/**
* UUID property.
*
* @param <R> the root query bean type
*/
public class PUuid<R> extends PBaseValueEqual<R,UUID> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PUuid(String name, R root) {
super(name , root);
}
/**
* Construct with additional path prefix.
*/
public PUuid(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.Year;
/**
* Year property.
*
* @param <R> the root query bean type
*/
public class PYear<R> extends PBaseNumber<R,Year> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PYear(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PYear(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,28 @@
package io.ebean.typequery;
import java.time.YearMonth;
/**
* YearMonth property.
*
* @param <R> the root query bean type
*/
public class PYearMonth<R> extends PBaseDate<R,YearMonth> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PYearMonth(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PYearMonth(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.time.ZoneId;
/**
* ZoneId property.
*
* @param <R> the root query bean type
*/
public class PZoneId<R> extends PBaseValueEqual<R,ZoneId> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PZoneId(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PZoneId(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,29 @@
package io.ebean.typequery;
import java.time.ZoneOffset;
/**
* ZoneOffset property.
*
* @param <R> the root query bean type
*/
public class PZoneOffset<R> extends PBaseValueEqual<R,ZoneOffset> {
/**
* Construct with a property name and root instance.
*
* @param name property name
* @param root the root query bean instance
*/
public PZoneOffset(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public PZoneOffset(String name, R root, String prefix) {
super(name, root, prefix);
}
}
@@ -0,0 +1,251 @@
package io.ebean.typequery;
import io.ebean.ExpressionList;
/**
* Base type for associated beans.
*
* @param <T> the entity bean type (normal entity bean type e.g. Customer)
* @param <R> the specific root query bean type (e.g. QCustomer)
*/
@SuppressWarnings("rawtypes")
public abstract class TQAssocBean<T, R> extends TQProperty<R> {
/**
* Construct with a property name and root instance.
*
* @param name the name of the property
* @param root the root query bean instance
*/
public TQAssocBean(String name, R root) {
this(name, root, null);
}
/**
* Construct with additional path prefix.
*/
public TQAssocBean(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Eagerly fetch this association fetching all the properties.
*/
public R fetch() {
((TQRootBean) _root).query().fetch(_name);
return _root;
}
/**
* Eagerly fetch this association using a "query join".
*/
public R fetchQuery() {
((TQRootBean) _root).query().fetchQuery(_name);
return _root;
}
/**
* Eagerly fetch this association using L2 bean cache.
* Cache misses are populated via fetchQuery().
*/
public R fetchCache() {
((TQRootBean) _root).query().fetchCache(_name);
return _root;
}
/**
* Use lazy loading for fetching this association.
*/
public R fetchLazy() {
((TQRootBean) _root).query().fetchLazy(_name);
return _root;
}
/**
* Eagerly fetch this association with the properties specified.
*/
public R fetch(String properties) {
((TQRootBean) _root).query().fetch(_name, properties);
return _root;
}
/**
* Eagerly fetch this association using a "query join" with the properties specified.
*/
public R fetchQuery(String properties) {
((TQRootBean) _root).query().fetchQuery(_name, properties);
return _root;
}
/**
* Eagerly fetch this association using L2 cache with the properties specified.
* Cache misses are populated via fetchQuery().
*/
public R fetchCache(String properties) {
((TQRootBean) _root).query().fetchCache(_name, properties);
return _root;
}
/**
* Deprecated in favor of fetch().
*
* @deprecated
*/
public R fetchAll() {
return fetch();
}
/**
* Eagerly fetch this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchProperties(TQProperty<?>... props) {
((TQRootBean) _root).query().fetch(_name, properties(props));
return _root;
}
/**
* Eagerly fetch query this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchQueryProperties(TQProperty<?>... props) {
((TQRootBean) _root).query().fetchQuery(_name, properties(props));
return _root;
}
/**
* Eagerly fetch this association using L2 bean cache.
*/
@SafeVarargs
protected final R fetchCacheProperties(TQProperty<?>... props) {
((TQRootBean) _root).query().fetchCache(_name, properties(props));
return _root;
}
/**
* Eagerly fetch query this association fetching some of the properties.
*/
@SafeVarargs
protected final R fetchLazyProperties(TQProperty<?>... props) {
((TQRootBean) _root).query().fetchLazy(_name, properties(props));
return _root;
}
/**
* Append the properties as a comma delimited string.
*/
@SafeVarargs
protected final String properties(TQProperty<?>... props) {
StringBuilder selectProps = new StringBuilder(50);
for (int i = 0; i < props.length; i++) {
if (i > 0) {
selectProps.append(",");
}
selectProps.append(props[i].propertyName());
}
return selectProps.toString();
}
/**
* Is equal to by ID property.
*/
public R eq(T other) {
expr().eq(_name, other);
return _root;
}
/**
* Is equal to by ID property.
*/
public R equalTo(T other) {
return eq(other);
}
/**
* Is not equal to by ID property.
*/
public R ne(T other) {
expr().ne(_name, other);
return _root;
}
/**
* Is not equal to by ID property.
*/
public R notEqualTo(T other) {
return ne(other);
}
/**
* Apply a filter when fetching these beans.
*/
public R filterMany(ExpressionList<T> filter) {
@SuppressWarnings("unchecked")
ExpressionList<T> expressionList = (ExpressionList<T>) expr().filterMany(_name);
expressionList.addAll(filter);
return _root;
}
/**
* Apply a filter when fetching these beans.
* <p>
* The expressions can use any valid Ebean expression and contain
* placeholders for bind values using <code>?</code> or <code>?1</code> style.
* </p>
*
* <pre>{@code
*
* new QCustomer()
* .name.startsWith("Postgres")
* .contacts.filterMany("firstName istartsWith ?", "Rob")
* .findList();
*
* }</pre>
*
* <pre>{@code
*
* new QCustomer()
* .name.startsWith("Postgres")
* .contacts.filterMany("whenCreated inRange ? to ?", startDate, endDate)
* .findList();
*
* }</pre>
*
* @param expressions The expressions including and, or, not etc with ? and ?1 bind params.
* @param params The bind parameter values
*/
public R filterMany(String expressions, Object... params) {
expr().filterMany(_name, expressions, params);
return _root;
}
/**
* Is empty for a collection property.
* <p>
* This effectively adds a not exists sub-query on the collection property.
* </p>
* <p>
* This expression only works on OneToMany and ManyToMany properties.
* </p>
*/
public R isEmpty() {
expr().isEmpty(_name);
return _root;
}
/**
* Is not empty for a collection property.
* <p>
* This effectively adds an exists sub-query on the collection property.
* </p>
* <p>
* This expression only works on OneToMany and ManyToMany properties.
* </p>
*/
public R isNotEmpty() {
expr().isNotEmpty(_name);
return _root;
}
}
@@ -0,0 +1,14 @@
package io.ebean.typequery;
/**
* Helper for adding a path prefix to a property.
*/
public class TQPath {
/**
* Return the full path by adding the prefix to the property name (null safe).
*/
public static String add(String prefix, String name) {
return (prefix == null) ? name : prefix+"."+name;
}
}
@@ -0,0 +1,68 @@
package io.ebean.typequery;
import io.ebean.ExpressionList;
/**
* A property used in type query.
*
* @param <R> The type of the owning root bean
*/
public class TQProperty<R> {
protected final String _name;
protected final R _root;
/**
* Construct with a property name and root instance.
*
* @param name the name of the property
* @param root the root query bean instance
*/
public TQProperty(String name, R root) {
this(name, root, null);
}
/**
* Construct with additional path prefix.
*/
public TQProperty(String name, R root, String prefix) {
this._root = root;
this._name = TQPath.add(prefix, name);
}
public String toString() {
return _name;
}
/**
* Internal method to return the underlying expression list.
*/
protected ExpressionList<?> expr() {
return ((TQRootBean) _root).peekExprList();
}
/**
* Return the property name.
*/
protected String propertyName() {
return _name;
}
/**
* Is null.
*/
public R isNull() {
expr().isNull(_name);
return _root;
}
/**
* Is not null.
*/
public R isNotNull() {
expr().isNotNull(_name);
return _root;
}
}
@@ -0,0 +1,43 @@
package io.ebean.typequery;
/**
* Base scalar property.
*
* @param <R> The type of the owning root bean
*/
public class TQPropertyBase<R> extends TQProperty<R> {
/**
* Construct with a property name and root instance.
*
* @param name the name of the property
* @param root the root query bean instance
*/
public TQPropertyBase(String name, R root) {
super(name, root);
}
/**
* Construct with additional path prefix.
*/
public TQPropertyBase(String name, R root, String prefix) {
super(name, root, prefix);
}
/**
* Order by ascending on this property.
*/
public R asc() {
expr().order().asc(_name);
return _root;
}
/**
* Order by descending on this property.
*/
public R desc() {
expr().order().desc(_name);
return _root;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
package io.ebean.typequery;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to denote a type query bean.
* <p>
* These are typically generated beans used to build queries using type safe query criteria.
* </p>
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeQueryBean {
/**
* The version description for the query bean.
*/
String value() default "v0";
}
@@ -0,0 +1,37 @@
/**
* Provides type safe query criteria support for Ebean ORM queries.
* <p>
* 'Query beans' like QCustomer are generated using the <code>avaje-ebeanorm-typequery-generator</code>
* for each entity bean type and can then be used to build queries with type safe criteria.
* </p>
*
* <h2>Example - usage of QCustomer</h2>
* <pre>{@code
*
* Date fiveDaysAgo = ...
*
* List<Customer> customers =
* new QCustomer()
*
* // name is a known property of type string so
* // it has relevant expressions such as like, startsWith etc
* .name.ilike("rob")
*
* // status is a specific Enum type is equalTo() in() etc
* .status.equalTo(Customer.Status.GOOD)
*
* // registered is a date type with after(), before() etc
* .registered.after(fiveDaysAgo)
*
* // contacts is an associated bean containing specific
* // properties and in this case we use email which is a string type
* .contacts.email.endsWith("@foo.com")
*
* .orderBy()
* .name.asc()
* .registered.desc()
* .findList();
*
* }</pre>
*/
package io.ebean.typequery;
@@ -0,0 +1,92 @@
package io.ebean.typequery;
import io.ebeaninternal.server.expression.DefaultExpressionList;
import io.ebeaninternal.server.expression.SimpleExpression;
import org.example.domain.Customer;
import org.example.domain.query.QCustomer;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class PBooleanTest {
PBoolean<QCustomer> property(QCustomer customer) {
return new PBoolean<>("active", customer);
}
@Test
public void constructWithPrefix() throws Exception {
QCustomer customer = new QCustomer();
PBoolean<QCustomer> property = new PBoolean<>("active", customer, null);
property.isTrue();
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.TRUE);
}
@Test
public void isTrue() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.isTrue();
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.TRUE);
}
@Test
public void isFalse() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.isFalse();
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.FALSE);
}
@Test
public void is_false() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.is(false);
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.FALSE);
}
@Test
public void is_true() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.is(true);
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.TRUE);
}
@Test
public void eq_true() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.eq(true);
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.TRUE);
}
@Test
public void eq_false() throws Exception {
QCustomer customer = new QCustomer();
PBoolean property = property(customer);
property.eq(false);
assertThat(getExpression(customer).getValue()).isEqualTo(Boolean.FALSE);
}
private SimpleExpression getExpression(QCustomer customer) {
DefaultExpressionList<Customer> where = (DefaultExpressionList<Customer>)customer.query().where();
return (SimpleExpression)where.getUnderlyingList().get(0);
}
}
@@ -0,0 +1,16 @@
package org.example.domain;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorValue("CAT")
@Entity
public class ACat extends Animal {
public ACat(String name) {
super(name);
}
}
@@ -0,0 +1,26 @@
package org.example.domain;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorValue("DOG")
@Entity
public class ADog extends Animal {
private String registration;
public ADog(String name, String registration) {
super(name);
this.registration = registration;
}
public String getRegistration() {
return registration;
}
public void setRegistration(String registration) {
this.registration = registration;
}
}
@@ -0,0 +1,16 @@
package org.example.domain;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
@Inheritance
@DiscriminatorValue("WC")
@Entity
public class AWildCat extends ACat {
public AWildCat(String name) {
super(name);
}
}
@@ -0,0 +1,100 @@
package org.example.domain;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.Size;
/**
* Address entity bean.
*/
@Entity
@Table(name = "o_address")
public class Address extends BaseModel {
@Size(max = 100)
String line1;
@Size(max = 100)
String line2;
@Size(max = 100)
String city;
@ManyToOne
Country country;
/**
* Create a copy of the address. Used to provide a 'snapshot' of
* the shippingAddress for a give order.
*/
public Address createCopy() {
Address copy = new Address();
copy.setLine1(line1);
copy.setLine2(line2);
copy.setCity(city);
copy.setCountry(country);
return copy;
}
public String toString() {
return id + " " + line1 + " " + line2 + " " + city + " " + country;
}
/**
* Return line 1.
*/
public String getLine1() {
return line1;
}
/**
* Set line 1.
*/
public void setLine1(String line1) {
this.line1 = line1;
}
/**
* Return line 2.
*/
public String getLine2() {
return line2;
}
/**
* Set line 2.
*/
public void setLine2(String line2) {
this.line2 = line2;
}
/**
* Return city.
*/
public String getCity() {
return city;
}
/**
* Set city.
*/
public void setCity(String city) {
this.city = city;
}
/**
* Return country.
*/
public Country getCountry() {
return country;
}
/**
* Set country.
*/
public void setCountry(Country country) {
this.country = country;
}
}
@@ -0,0 +1,49 @@
package org.example.domain;
import io.ebean.Model;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.Version;
@Entity
@Inheritance
public abstract class Animal extends Model {
@Id
long id;
@Version
long version;
String name;
public Animal(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,69 @@
package org.example.domain;
import io.ebean.Model;
import io.ebean.annotation.CreatedTimestamp;
import io.ebean.annotation.UpdatedTimestamp;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import java.sql.Timestamp;
/**
* Base domain object with Id, version, whenCreated and whenUpdated.
*
* <p>
* Extending Model to enable the 'active record' style.
*
* <p>
* whenCreated and whenUpdated are generally useful for maintaining external search services (like
* elasticsearch) and audit.
*/
@MappedSuperclass
public abstract class BaseModel extends Model {
@Id
Long id;
@Version
Long version;
@CreatedTimestamp
Timestamp whenCreated;
@UpdatedTimestamp
Timestamp whenUpdated;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
public Timestamp getWhenCreated() {
return whenCreated;
}
public void setWhenCreated(Timestamp whenCreated) {
this.whenCreated = whenCreated;
}
public Timestamp getWhenUpdated() {
return whenUpdated;
}
public void setWhenUpdated(Timestamp whenUpdated) {
this.whenUpdated = whenUpdated;
}
}
@@ -0,0 +1,110 @@
package org.example.domain;
import io.ebean.annotation.DbArray;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.List;
/**
* Contact entity bean.
*/
@Entity
@Table(name="be_contact")
public class Contact extends BaseModel {
@DbArray
List<String> phoneNumbers = new ArrayList();
@Column(length=50)
String firstName;
@Column(length=50)
String lastName;
@Column(length=200)
String email;
@Column(length=20)
String phone;
@ManyToOne(optional=false)
Customer customer;
@OneToMany(mappedBy = "contact")
List<ContactNote> notes;
/**
* Default constructor.
*/
public Contact() {
}
/**
* Construct with a firstName and lastName.
*/
public Contact(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public List<ContactNote> getNotes() {
return notes;
}
public void setNotes(List<ContactNote> notes) {
this.notes = notes;
}
public List<String> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<String> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
@@ -0,0 +1,46 @@
package org.example.domain;
import io.ebean.Finder;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
@Entity
public class ContactNote extends BaseModel {
public static final Finder<Long, ContactNote> find = new Finder<>(ContactNote.class);
@ManyToOne(optional = false)
Contact contact;
String title;
@Lob
String note;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Contact getContact() {
return contact;
}
public void setContact(Contact contact) {
this.contact = contact;
}
}
@@ -0,0 +1,59 @@
package org.example.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Country entity bean.
*/
@Entity
@Table(name="o_country")
public class Country {
@Id
//@Size(max=2)
String code;
//@Size(max=60)
String name;
public Country(String code, String name) {
this.code = code;
this.name = name;
}
public String toString() {
return code;
}
/**
* Return code.
*/
public String getCode() {
return code;
}
/**
* Set code.
*/
public void setCode(String code) {
this.code = code;
}
/**
* Return name.
*/
public String getName() {
return name;
}
/**
* Set name.
*/
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,172 @@
package org.example.domain;
import io.ebean.annotation.Cache;
import io.ebean.annotation.EnumValue;
import io.ebean.types.Inet;
import org.example.domain.finder.CustomerFinder;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.otherpackage.ValidEmail;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Customer entity bean.
*/
@Cache
@Entity
@Table(name = "be_customer")
public class Customer extends BaseModel {
/**
* Convenience Finder for 'active record' style.
*/
public static final CustomerFinder find = new CustomerFinder();
public enum Status {
@EnumValue("G")
GOOD,
@EnumValue("B")
BAD,
@EnumValue("M")
MIDDLING
}
Status status;
boolean inactive;
PhoneNumber phoneNumber;
ValidEmail email;
@Column(length = 100)
String name;
Date registered;
Inet currentInet;
@Column(length = 1000)
String comments;
@ManyToOne(cascade = CascadeType.ALL)
Address billingAddress;
@ManyToOne(cascade = CascadeType.ALL)
Address shippingAddress;
@OneToMany(mappedBy = "customer", cascade = CascadeType.PERSIST)
List<Contact> contacts;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public boolean isInactive() {
return inactive;
}
public void setInactive(boolean inactive) {
this.inactive = inactive;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getRegistered() {
return registered;
}
public void setRegistered(Date registered) {
this.registered = registered;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Inet getCurrentInet() {
return currentInet;
}
public void setCurrentInet(Inet currentInet) {
this.currentInet = currentInet;
}
public Address getBillingAddress() {
return billingAddress;
}
public void setBillingAddress(Address billingAddress) {
this.billingAddress = billingAddress;
}
public Address getShippingAddress() {
return shippingAddress;
}
public void setShippingAddress(Address shippingAddress) {
this.shippingAddress = shippingAddress;
}
public List<Contact> getContacts() {
return contacts;
}
public void setContacts(List<Contact> contacts) {
this.contacts = contacts;
}
public PhoneNumber getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(final PhoneNumber phoneNumber) {
this.phoneNumber = phoneNumber;
}
public ValidEmail getEmail() {
return email;
}
public void setEmail(final ValidEmail email) {
this.email = email;
}
/**
* Helper method to add a contact to the customer.
*/
public void addContact(Contact contact) {
if (contacts == null) {
contacts = new ArrayList<>();
}
// setting the customer is automatically done when Ebean does
// a cascade save from customer to contacts.
contact.setCustomer(this);
contacts.add(contact);
}
}
@@ -0,0 +1,137 @@
package org.example.domain;
import io.ebean.Finder;
import io.ebean.Model;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
/**
* Order entity bean.
*/
@Entity
@Table(name = "o_order")
public class Order extends BaseModel {
public static final Finder<Long,Order> find = new Finder<>(Order.class);
public enum Status {
NEW, APPROVED, SHIPPED, COMPLETE
}
Status status;
Date orderDate;
Date shipDate;
@NotNull
@ManyToOne
Customer customer;
@ManyToOne
Address shippingAddress;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
@OrderBy("id asc")
List<OrderDetail> details;
public String toString() {
return id + " status:" + status + " customer:" + customer;
}
/**
* Return order date.
*/
public Date getOrderDate() {
return orderDate;
}
/**
* Set order date.
*/
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
/**
* Return ship date.
*/
public Date getShipDate() {
return shipDate;
}
/**
* Set ship date.
*/
public void setShipDate(Date shipDate) {
this.shipDate = shipDate;
}
/**
* Return status.
*/
public Status getStatus() {
return status;
}
/**
* Set status.
*/
public void setStatus(Status status) {
this.status = status;
}
/**
* Return customer.
*/
public Customer getCustomer() {
return customer;
}
/**
* Set customer.
*/
public void setCustomer(Customer customer) {
this.customer = customer;
}
/**
* Set the customer with their current shipping address.
*/
public void setCustomerWithShipping(Customer customer) {
this.customer = customer;
this.shippingAddress = customer.getShippingAddress();
}
/**
* Return details.
*/
public List<OrderDetail> getDetails() {
return details;
}
/**
* Set details.
*/
public void setDetails(List<OrderDetail> details) {
this.details = details;
}
public void addDetail(OrderDetail detail) {
if (details == null) {
details = new ArrayList<>();
}
details.add(detail);
}
}
@@ -0,0 +1,99 @@
package org.example.domain;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* Order Detail entity bean.
*/
@Entity
@Table(name = "o_order_detail")
public class OrderDetail extends BaseModel {
@ManyToOne
Order order;
Integer orderQty;
Integer shipQty;
Double unitPrice;
@ManyToOne
Product product;
public OrderDetail() {
}
public OrderDetail(Product product, Integer orderQty, Double unitPrice) {
this.product = product;
this.orderQty = orderQty;
this.unitPrice = unitPrice;
}
/**
* Return order qty.
*/
public Integer getOrderQty() {
return orderQty;
}
/**
* Set order qty.
*/
public void setOrderQty(Integer orderQty) {
this.orderQty = orderQty;
}
/**
* Return ship qty.
*/
public Integer getShipQty() {
return shipQty;
}
/**
* Set ship qty.
*/
public void setShipQty(Integer shipQty) {
this.shipQty = shipQty;
}
public Double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(Double unitPrice) {
this.unitPrice = unitPrice;
}
/**
* Return order.
*/
public Order getOrder() {
return order;
}
/**
* Set order.
*/
public void setOrder(Order order) {
this.order = order;
}
/**
* Return product.
*/
public Product getProduct() {
return product;
}
/**
* Set product.
*/
public void setProduct(Product product) {
this.product = product;
}
}
@@ -0,0 +1,47 @@
package org.example.domain;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.Size;
/**
* Product entity bean.
*/
@Entity
@Table(name = "o_product")
public class Product extends BaseModel {
@Size(max = 20)
String sku;
String name;
/**
* Return sku.
*/
public String getSku() {
return sku;
}
/**
* Set sku.
*/
public void setSku(String sku) {
this.sku = sku;
}
/**
* Return name.
*/
public String getName() {
return name;
}
/**
* Set name.
*/
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,19 @@
package org.example.domain;
import java.util.ArrayList;
public class SomePojo {
String name;
ArrayList<String> foos = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,18 @@
package org.example.domain.finder;
import io.ebean.Finder;
import org.example.domain.Customer;
import org.example.domain.query.QCustomer;
/**
*/
public class CustomerFinder extends Finder<Long,Customer> {
public CustomerFinder() {
super(Customer.class);
}
public QCustomer typed() {
return new QCustomer();
}
}
@@ -0,0 +1,4 @@
package org.example.domain.otherpackage;
public interface Email<T> extends Comparable<T> {
}
@@ -0,0 +1,17 @@
package org.example.domain.otherpackage;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class PhoneAttributeConverter implements AttributeConverter<PhoneNumber, String> {
@Override
public String convertToDatabaseColumn(final PhoneNumber attribute) {
return attribute.getMsisdn();
}
@Override
public PhoneNumber convertToEntityAttribute(final String dbData) {
return new PhoneNumber(dbData);
}
}
@@ -0,0 +1,13 @@
package org.example.domain.otherpackage;
public class PhoneNumber {
private final String msisdn;
public PhoneNumber(final String msisdn) {
this.msisdn = msisdn;
}
public String getMsisdn() {
return msisdn;
}
}
@@ -0,0 +1,18 @@
package org.example.domain.otherpackage;
public class ValidEmail implements Email<ValidEmail> {
private final String emailAddress;
public ValidEmail(final String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return emailAddress;
}
@Override
public int compareTo(final ValidEmail o) {
return emailAddress.compareTo(o.emailAddress);
}
}
@@ -0,0 +1,17 @@
package org.example.domain.otherpackage;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class ValidEmailAttributeConverter implements AttributeConverter<ValidEmail, String> {
@Override
public String convertToDatabaseColumn(final ValidEmail attribute) {
return attribute.getEmailAddress();
}
@Override
public ValidEmail convertToEntityAttribute(final String dbData) {
return new ValidEmail(dbData);
}
}
@@ -0,0 +1,62 @@
package org.querytest;
import org.example.domain.Customer;
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
public class QCustomerAndOrTest {
@Test
public void testEndAnd() {
Date fiveDays = fiveDaysAgo();
Customer.find.typed()
.status.equalTo(Customer.Status.GOOD)
.or()
.id.greaterThan(1000)
.and()
.name.startsWith("super")
.registered.after(fiveDays)
.endAnd()
.orderBy().id.desc()
.findList();
}
@Test
public void testQuery() {
Date fiveDays = fiveDaysAgo();
Customer.find.typed().name.like("DoesNotExist").delete();
List<Customer> customers =
Customer.find.typed()
.status.equalTo(Customer.Status.GOOD)
.or()
.id.greaterThan(1000)
.and()
.name.startsWith("super")
.registered.after(fiveDays)
.endJunction()
.orderBy().id.desc()
.findList();
// where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) order by t0.id desc; --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
// where t0.status = ? and (t0.id > ? or (t0.name like ? and t0.registered > ? ) ) order by t0.id; --bind(GOOD,1000,super%,Wed Jul 22 00:00:00 NZST 2015)
// //where t0.id > ? and (t0.id < ? or (t0.name like ? and t0.name like ? ) ) order by t0.id; --bind(12,1234,one,two)
//
}
private Date fiveDaysAgo() {
LocalDateTime fiveDaysAgo = LocalDate.now().atStartOfDay().minusDays(5);
return new Date(fiveDaysAgo.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
}
}
@@ -0,0 +1,37 @@
package org.querytest;
import org.example.domain.Customer;
import org.example.domain.query.QCustomer;
import org.junit.Test;
import java.util.Date;
import java.util.List;
public class QCustomerSimpleLikeQueryTest {
@Test
public void testQuery() {
List<Customer> customers =
new QCustomer()
.name.ilike("rob")
.status.equalTo(Customer.Status.GOOD)
.registered.after(new Date())
.contacts.email.endsWith("@foo.com")
.orderBy()
.name.asc()
.registered.desc()
.findList();
//where lower(t0.name) like ? and t0.status = ? and t0.registered > ? and u1.email like ? order by t0.name, t0.registered desc; --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com)
}
@Test
public void testFindEach() {
new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.orderBy().id.asc()
.findEach(customer -> System.out.println("-- visit " + customer));
}
}
@@ -0,0 +1,842 @@
package org.querytest;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.PagedList;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
import io.ebean.annotation.Transactional;
import io.ebean.types.Inet;
import org.example.domain.ACat;
import org.example.domain.ADog;
import org.example.domain.Address;
import org.example.domain.Animal;
import org.example.domain.Country;
import org.example.domain.Customer;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.otherpackage.ValidEmail;
import org.example.domain.query.QAnimal;
import org.example.domain.query.QContact;
import org.example.domain.query.QCustomer;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.example.domain.query.QAddress.Alias.country;
import static org.example.domain.query.QAddress.Alias.line1;
import static org.example.domain.query.QContact.Alias.lastName;
import static org.example.domain.query.QCustomer.Alias.billingAddress;
public class QCustomerTest {
@Rule
public final TestName testName = new TestName();
@Test
public void findWithTransaction() {
final Database database = DB.getDefault();
try (Transaction txn = database.createTransaction()) {
Customer customer = new Customer();
customer.setName("explicitTransaction");
database.save(customer, txn);
final Customer found = new QCustomer(txn)
.name.eq("explicitTransaction")
.findOne();
assertThat(found).isNotNull();
// not found using other transaction
final Customer foundNot = new QCustomer()
.name.eq("explicitTransaction")
.findOne();
assertThat(foundNot).isNull();
txn.commit();
}
}
@Test
public void findSingleAttribute() {
List<String> names = new QCustomer()
.setDistinct(true)
.select(QCustomer.alias().name)
.status.equalTo(Customer.Status.BAD)
.findSingleAttributeList();
assertThat(names).isNotNull();
}
@Test
public void findIterate() {
Customer cust = new Customer();
cust.setName("foo");
cust.setStatus(Customer.Status.GOOD);
cust.save();
List<Long> ids = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIds();
assertThat(ids).isNotEmpty();
Map<List, Customer> map = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findMap();
assertThat(map.size()).isEqualTo(ids.size());
QueryIterator<Customer> iterate = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIterate();
try {
while (iterate.hasNext()) {
Customer customer = iterate.next();
assertThat(customer.getName()).isNotNull();
}
} finally {
iterate.close();
}
}
@Test
public void isEmpty() {
new QCustomer()
.contacts.isEmpty()
.findList();
new QCustomer()
.contacts.isNotEmpty()
.findList();
}
@Transactional
@Test
public void forUpdate() {
new QCustomer()
.id.eq(42)
.forUpdate()
.findOne();
new QCustomer()
.id.eq(42)
.forUpdateNoWait()
.findOne();
new QCustomer()
.id.eq(42)
.forUpdateSkipLocked()
.findOne();
}
@Ignore
@Test
public void arrayContains() {
new QContact()
.phoneNumbers.contains("4312")
.findList();
new QCustomer()
.contacts.phoneNumbers.contains("4312")
.findList();
}
@Test
public void setIncludeSoftDeletes() {
new QCustomer()
.setIdIn(42L)
.setIncludeSoftDeletes()
.findList();
}
@Test
public void testIdIn() {
new QCustomer()
.setIdIn("1", "2")
.findList();
new QCustomer()
.id.in(1L, 2L, 3L)
.findList();
}
@Test
public void testIn() {
new QCustomer()
.id.in(34L, 33L)
.name.in("asd", "foo", "bar")
.registered.in(new Date())
.findList();
}
@Test
public void usingTransaction() {
try (Transaction transaction = DB.getDefault().createTransaction()) {
new QCustomer()
.registered.isNull()
.usingTransaction(transaction)
.findList();
}
}
@Test
public void usingConnection() throws SQLException {
Customer cust = new Customer();
cust.setName("usingConnection");
cust.setStatus(Customer.Status.GOOD);
cust.save();
DataSource dataSource = DB.getDefault().getPluginApi().getDataSource();
try (Connection connection = dataSource.getConnection()) {
List<Customer> foo = new QCustomer()
.name.eq("usingConnection")
.usingConnection(connection)
.findList();
assertThat(foo).hasSize(1);
}
}
@Test
public void testAssocOne() {
Address address = new Address();
address.setId(41L);
new QCustomer()
.billingAddress.eq(address)
.findList();
new QCustomer()
.billingAddress.equalTo(address)
.findList();
new QCustomer()
.billingAddress.ne(address)
.findList();
new QCustomer()
.billingAddress.notEqualTo(address)
.findList();
}
@Test
public void testInOrEmpty() {
List<String> names = Arrays.asList("asd", "foo", "bar");
new QCustomer()
.registered.before(new Date())
.name.inOrEmpty(names)
.findList();
new QCustomer()
.registered.before(new Date())
.name.inOrEmpty(null)
.findList();
names = Collections.emptyList();
new QCustomer()
.registered.before(new Date())
.name.inOrEmpty(names)
.findList();
}
@Test
public void testNotIn() {
new QCustomer()
.id.isIn(34L, 33L)
.name.notIn("asd", "foo", "bar")
.registered.in(new Date())
.findList();
}
@Test
public void testQueryBoolean() {
new QCustomer()
.name.contains("rob")
//.setUseDocStore(true)
.setMaxRows(10)
.findPagedList();
new QCustomer()
.inactive.isFalse()
.findList();
}
@Test
public void testFindOne() {
new QCustomer()
.name.isIn("rob", "foo")
//.setUseDocStore(true)
.setMaxRows(1)
.findOne();
Optional<Customer> maybe = new QCustomer()
.name.contains("rob")
//.setUseDocStore(true)
.setMaxRows(1)
.findOneOrEmpty();
maybe.isPresent();
new QCustomer()
.inactive.isFalse()
.findList();
}
private void insertCustomer(String name) {
Customer cust = new Customer();
cust.setName(name);
cust.setStatus(Customer.Status.GOOD);
cust.save();
}
@Test
public void testFindStream() {
insertCustomer("stream1");
insertCustomer("stream2");
StringJoiner sb = new StringJoiner("|");
try (Stream<Customer> stream = new QCustomer()
.name.startsWith("stream")
.id.asc()
.findStream()) {
stream.forEach(it -> sb.add(it.getName()));
}
assertThat(sb.toString()).isEqualTo("stream1|stream2");
}
@Test
public void testFindLargeStream() {
insertCustomer("largeStream1");
insertCustomer("largeStream2");
insertCustomer("largeStream3");
StringJoiner sb = new StringJoiner("|");
try (Stream<Customer> stream = new QCustomer()
.name.startsWith("largeStream")
.id.asc()
.findLargeStream()) {
stream.forEach(it -> sb.add(it.getName()));
}
assertThat(sb.toString()).isEqualTo("largeStream1|largeStream2|largeStream3");
}
@Test
public void testFilterMany() {
Customer cust = new Customer();
cust.setName("Postgres Foo");
cust.setStatus(Customer.Status.GOOD);
cust.save();
new QCustomer()
.name.startsWith("Postgres")
.contacts.filterMany("firstName istartsWith ?", "Rob")
.findList();
final LocalDate startDate = LocalDate.now().minusDays(7);
final LocalDate endDate = LocalDate.now();
new QCustomer()
.name.startsWith("Postgres")
.contacts.filterMany("whenCreated inRange ? to ?", startDate, endDate)
.findList();
}
@Test
public void testDate_lessThan() {
assertContains(new QCustomer().registered.lt(new Date()).query(), " where t0.registered < ?");
assertContains(new QCustomer().registered.before(new Date()).query(), " where t0.registered < ?");
assertContains(new QCustomer().registered.lessThan(new Date()).query(), " where t0.registered < ?");
}
@Test
public void testDate_lessOrEqualTo() {
assertContains(new QCustomer().registered.le(new Date()).query(), " where t0.registered <= ?");
assertContains(new QCustomer().registered.lessOrEqualTo(new Date()).query(), " where t0.registered <= ?");
}
@Test
public void testDate_greaterThan() {
assertContains(new QCustomer().registered.after(new Date()).query(), " where t0.registered > ?");
assertContains(new QCustomer().registered.gt(new Date()).query(), " where t0.registered > ?");
assertContains(new QCustomer().registered.greaterThan(new Date()).query(), " where t0.registered > ?");
}
@Test
public void testDate_greaterOrEqualTo() {
assertContains(new QCustomer().registered.ge(new Date()).query(), " where t0.registered >= ?");
assertContains(new QCustomer().registered.greaterOrEqualTo(new Date()).query(), " where t0.registered >= ?");
}
private void assertContains(Query<Customer> query, String match) {
query.findList();
assertThat(query.getGeneratedSql()).contains(match);
}
@Test
public void query_setAllowLoadErrors() {
new QCustomer()
.status.in(Customer.Status.GOOD)
.setAllowLoadErrors()
.findList();
}
@Test
public void query_setInheritType() {
ACat cat = new ACat("C1");
cat.save();
ACat cat2 = new ACat("C2");
cat2.save();
ADog dog = new ADog("D1", "D878");
dog.save();
List<Animal> animals = new QAnimal()
.id.greaterOrEqualTo(1L)
.setInheritType(ACat.class)
.findList();
System.out.println(animals);
}
@Test
public void select_assocManyToOne() {
Country nz = new Country("NZ", "New Zealand");
DB.merge(nz);
Address address = new Address();
address.setLine1("42 below");
address.setCountry(nz);
Customer customer0 = new Customer();
customer0.setName("asdBilling0");
customer0.setBillingAddress(address);
customer0.save();
Customer customer1 = new Customer();
customer1.setName("asdBilling1");
customer1.setBillingAddress(new Address());
customer1.save();
List<Long> billingAddressIds
= new QCustomer()
.select(billingAddress)
.name.startsWith("asdBilling")
.findSingleAttributeList();
assertThat(billingAddressIds).hasSize(2);
Map<Long,Customer> map
= new QCustomer()
.billingAddress.id.asMapKey()
.name.startsWith("asdBilling")
.findMap();
assertThat(map).hasSize(2);
List<Customer> customers = new QCustomer()
.billingAddress.fetch(line1, country)
.findList();
assertThat(customers).isNotEmpty();
}
@Test
public void query_fetchString() {
Customer cust = new Customer();
cust.setName("baz");
cust.setCurrentInet(new Inet("129.1.1.4"));
cust.setStatus(Customer.Status.GOOD);
cust.save();
new QCustomer()
.currentInet.eq(Inet.of("129.1.1.4"))
.findList();
new QCustomer()
.currentInet.in(Inet.setOf("129.1.1.4","129.1.1.5"))
.findList();
new QCustomer()
.contacts.fetch("email")
.orderBy()
.name.asc()
.contacts.email.asc()
.findList();
new QCustomer()
.contacts.fetchQuery("email")
.orderBy()
.name.asc()
.contacts.email.asc()
.findList();
}
@Test
public void query_setBaseTable() {
new QCustomer()
.setBaseTable("BE_CUSTOMER")
.findList();
}
@Test
public void query_rawOrEmpty() {
List<String> names = Arrays.asList("A", "B");
new QCustomer()
.rawOrEmpty("name in (?1)", names)
.findList();
new QCustomer()
.rawOrEmpty("name in (?1)", null)
.findList();
new QCustomer()
.rawOrEmpty("name in (?1)", new ArrayList<Long>())
.findList();
}
@Test
public void query_orNull() {
new QCustomer()
.name.equalToOrNull("A")
.findList();
new QCustomer()
.name.eqOrNull("A")
.findList();
new QCustomer()
.name.greaterThanOrNull("B")
.findList();
new QCustomer()
.name.lessThanOrNull("C")
.findList();
new QCustomer()
.name.gtOrNull("GT1")
.name.geOrNull("GE1")
.name.ltOrNull("LT1")
.name.leOrNull("LE1")
.findList();
}
@Test
public void query_inRange() {
new QCustomer()
.name.inRange("A", "B")
.findList();
new QCustomer()
.name.greaterOrEqualTo("A")
.name.lessThan("B")
.findList();
new QContact()
.firstName.inRangeWith(lastName, "B")
.findList();
}
@Test
public void query_exists() {
boolean customerExists =
new QCustomer()
.name.equalTo("DoesNotExistReally")
.exists();
assertThat(customerExists).isFalse();
}
@Test
public void testQuery() {
QContact contact = QContact.alias();
QCustomer cust = QCustomer.alias();
new QCustomer()
// tune query
.select(cust.name)
.status.isIn(Customer.Status.BAD, Customer.Status.BAD)
.contacts.fetch()
// predicates
.findList();
new QCustomer()
// tune query
.select(cust.name)
.contacts.fetch()
// predicates
.findList();
new QCustomer()
// tune query
.select(cust.id, cust.name)
.contacts.fetch(contact.firstName, contact.lastName, contact.email)
// predicates
.id.greaterThan(1)
.findList();
PagedList<Customer> pagedList = new QCustomer()
// tune query
.select(cust.id, cust.name)
.contacts.fetch(contact.firstName, contact.lastName, contact.email)
// predicates
.id.greaterThan(1)
.setFirstRow(20)
.setMaxRows(10)
.findPagedList();
pagedList.getList();
pagedList.getList();
// new QCustomer()
// .asDraft()
// .findList();
//
// new QCustomer()
// .includeSoftDeletes()
// .findList();
// List<Contact> contacts
// = new QContact()
// .email.like("asd")
// .notes.title.like("asd")
// .orderBy()
// .id.desc()
// .findList();
//
// List<Customer> customers = new QCustomer()
// .id.eq(1234)
// .status.equalTo(Customer.Status.BAD)
// .status.in(Customer.Status.GOOD, Customer.Status.MIDDLING)
// //.status.eq(Order.Status.APPROVED)
// .name.like("asd")
// .name.istartsWith("ASdf")
// .registered.after(new Date())
// .contacts.email.endsWith("@foo.com")
// .contacts.notes.id.greaterThan(123L)
// .orderBy().id.asc()
// .findList();
// //Customer customer3 =
// new QCustomer()
// .id.gt(12)
// .or()
// .id.lt(1234)
// .and()
// .name.like("one")
// .name.like("two")
// .endAnd()
// .endOr()
// .orderBy().id.asc()
// .findList();
//
// //where t0.id > ? and (t0.id < ? or (t0.name like ? and t0.name like ? ) ) order by t0.id; --bind(12,1234,one,two)
//
//// List<Customer> customers
//// = new QCustomer()
//// .name.like("asd")
//// .findList();
//
// Customer.find.where()
// .gt("id", 1234)
// .disjunction().eq("id", 1234).like("name", "asd")
// .endJunction().findList();
// QCustomer cust = QCustomer.I;
// ExpressionList<Customer> expr = new QCustomer().expr();
// expr.eq(cust.contacts.email, 123);
}
@Test
public void testFindSet() {
Set<Customer> customerSet = new QCustomer().findSet();
Assert.assertNotNull(customerSet);
}
@Test
public void testFindMap() {
Customer cust = new Customer();
cust.setName("banana");
cust.setStatus(Customer.Status.GOOD);
cust.save();
Map<String, Customer> map = new QCustomer()
.id.greaterOrEqualTo(1L)
.name.asMapKey()
.findMap();
assertThat(map.get("banana")).isNotNull();
}
@Test
public void testAsUpdate() {
int rows = new QContact()
.notes.note.startsWith("Make Inactive")
.email.endsWith("@foo.com")
.asUpdate()
.setRaw("email = lower(email)")
//.set("inactive", true)
.update();
assertThat(rows).isEqualTo(0);
}
@Test
public void testSelectFormula() {
Customer cust = new Customer();
cust.setName("junk junk");
cust.setStatus(Customer.Status.GOOD);
cust.setRegistered(new Date());
cust.save();
java.util.Date maxDate = new QCustomer()
.select("max(registered)")
.findSingleAttribute();
assertThat(maxDate).isNotNull();
}
@Test
public void testFetchByScalarValue() {
Customer cust = new Customer();
cust.setName(testName.getMethodName());
cust.setPhoneNumber(new PhoneNumber("+18005555555"));
cust.save();
assertThat(new QCustomer()
.name.eq(testName.getMethodName())
.phoneNumber.eq(new PhoneNumber("+18005555555"))
.findOne()).isNotNull();
}
@Test
public void testFetchByComparableScalarValue() {
Customer cust = new Customer();
cust.setName(testName.getMethodName());
cust.setEmail(new ValidEmail("foo2@example.org"));
cust.save();
assertThat(new QCustomer()
.name.eq(testName.getMethodName())
.email.eq(new ValidEmail("foo2@example.org"))
.findOne()).isNotNull();
assertThat(new QCustomer()
.name.eq(testName.getMethodName())
.email.gt(new ValidEmail("foo2@example.org"))
.findOne()).isNull();
assertThat(new QCustomer()
.name.eq(testName.getMethodName())
.email.gt(new ValidEmail("foo1@example.org"))
.findOne()).isNotNull();
assertThat(new QCustomer()
.name.eq(testName.getMethodName())
.email.greaterOrEqualTo(new ValidEmail("foo2@example.org"))
.findOne()).isNotNull();
}
@Test
public void testFetchFormula() {
Customer cust = new Customer();
cust.setName("junk junk");
cust.setStatus(Customer.Status.GOOD);
cust.setRegistered(new Date());
cust.save();
List<C1dto> dtos = new QCustomer()
.select("id, name")
.asDto(C1dto.class)
.findList();
assertThat(dtos).isNotEmpty();
}
public static class C1dto {
final long id;
final String name;
public C1dto(long id, String name) {
this.id = id;
this.name = name;
}
}
}
@@ -0,0 +1,44 @@
package org.querytest;
import io.ebean.FetchGroup;
import org.example.domain.Order;
import org.example.domain.query.QCustomer;
import org.example.domain.query.QOrder;
import org.junit.Test;
public class QOrderTest {
private static final QCustomer cu = QCustomer.alias();
private static final QOrder or = QOrder.alias();
private static final FetchGroup<Order> fg = QOrder.forFetchGroup()
.select(or.status, or.shipDate)
.customer.fetchCache(cu.name, cu.status, cu.registered, cu.comments)
.buildFetchGroup();
@Test
public void fetchCache() {
new QOrder()
.status.eq(Order.Status.NEW)
.customer.fetchCache(cu.name, cu.registered)
.findList();
new QOrder()
.status.eq(Order.Status.NEW)
.customer.fetchCache()
.findList();
}
@Test
public void viaFetchGraph() {
new QOrder()
.status.eq(Order.Status.NEW)
.select(fg)
.findList();
}
}
@@ -0,0 +1,2 @@
entity-packages: org.example.domain
querybean-packages: org.example.domain,org.querytest
@@ -0,0 +1,12 @@
#load.properties.override=${home}/config/myapp.ebean.properties
ebean.ddl.generate=true
ebean.ddl.run=true
datasource.default=h2
datasource.h2.username=sa
datasource.h2.password=
datasource.h2.databaseUrl=jdbc:h2:mem:tests
datasource.h2.databaseDriver=org.h2.Driver
@@ -0,0 +1,35 @@
<configuration scan="true" scanPeriod="10 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="WARN">
<appender-ref ref="STDOUT"/>
</root>
<logger name="io.ebean" level="INFO"/>
<logger name="io.ebean.SQL" level="TRACE"/>
<logger name="io.ebean.TXN" level="TRACE"/>
<logger name="io.ebean.SUM" level="TRACE"/>
<logger name="io.ebean.DDL" level="TRACE"/>
<logger name="io.ebean.cache.QUERY" level="TRACE"/>
<logger name="io.ebean.cache.BEAN" level="TRACE"/>
<logger name="io.ebean.cache.COLL" level="TRACE"/>
<logger name="io.ebean.cache.NATKEY" level="TRACE"/>
<logger name="com.avaje.tests" level="DEBUG"/>
<logger name="io.ebeaninternal.server.cluster" level="DEBUG"/>
<logger name="io.ebeaninternal.server.lib" level="DEBUG"/>
<logger name="io.ebeaninternal.server.lib.sql" level="TRACE"/>
<logger name="io.ebeaninternal.server.transaction" level="TRACE"/>
</configuration>
+9
View File
@@ -0,0 +1,9 @@
# kotlin-querybean-generator
Annotation processor for generating Kotlin query beans for type safe query construction.
For Kotlin users these are preferred over Java query beans in that they use Kotlin properties
rather than Java public fields. This limits the query bean enhancement to just the beans themselves
where as with java query beans we need to enhance callers (as we are effectively simulating 'properties'
via java public fields and enhancement).
Refer to the documentation at: https://ebean.io/docs/query/query-beans
+42
View File
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.4.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>kotlin-querybean-generator</artifactId>
<dependencies>
<dependency>
<groupId>org.avaje.composite</groupId>
<artifactId>composite-testing</artifactId>
<version>3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<!-- Turn off annotation processing for building -->
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,51 @@
package io.ebean.querybean.generator;
import java.io.IOException;
import java.io.Writer;
/**
* Helper that wraps a writer with some useful methods to append content.
*/
class Append {
private final Writer writer;
Append(Writer writer) {
this.writer = writer;
}
Append append(String content) {
try {
writer.append(content);
return this;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
void close() {
try {
writer.flush();
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Append eol() {
try {
writer.append("\n");
return this;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Append content with formatted arguments.
*/
Append append(String format, Object... args) {
return append(String.format(format, args));
}
}
@@ -0,0 +1,37 @@
package io.ebean.querybean.generator;
interface Constants {
String AT_GENERATED = "@Generated(\"io.ebean.querybean.kotlin-generator\")";
String AT_TYPEQUERYBEAN = "@TypeQueryBean(\"v1\")";
String GENERATED_9 = "javax.annotation.processing.Generated";
String GENERATED_8 = "javax.annotation.Generated";
String MAPPED_SUPERCLASS = "javax.persistence.MappedSuperclass";
String INHERITANCE = "javax.persistence.Inheritance";
String ENTITY = "javax.persistence.Entity";
String EMBEDDABLE = "javax.persistence.Embeddable";
String CONVERTER = "javax.persistence.Converter";
String EBEAN_COMPONENT = "io.ebean.annotation.EbeanComponent";
String DBARRAY = "io.ebean.annotation.DbArray";
String DBJSON = "io.ebean.annotation.DbJson";
String DBJSONB = "io.ebean.annotation.DbJsonB";
String DBNAME = "io.ebean.annotation.DbName";
String TQROOTBEAN = "io.ebean.typequery.TQRootBean";
String TQASSOCBEAN = "io.ebean.typequery.TQAssocBean";
String TQPROPERTY = "io.ebean.typequery.TQProperty";
String TYPEQUERYBEAN = "io.ebean.typequery.TypeQueryBean";
String DATABASE = "io.ebean.Database";
String DB = "io.ebean.DB";
String FETCHGROUP = "io.ebean.FetchGroup";
String QUERY = "io.ebean.Query";
String TRANSACTION = "io.ebean.Transaction";
String MODULEINFO = "io.ebean.config.ModuleInfo";
String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf";
String METAINF_SERVICES_MODULELOADER = "META-INF/services/io.ebean.config.ModuleInfoLoader";
}
@@ -0,0 +1,55 @@
package io.ebean.querybean.generator;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import java.util.List;
import java.util.Map;
import java.util.Set;
class FindDbName {
/**
* Return the value of the DbName annotation or null if it isn't found on the element.
*/
static String value(TypeElement element, Types typeUtils) {
AnnotationMirror mirror = findDbNameMirror(element);
if (mirror != null) {
return readDbNameValue(mirror);
}
final TypeMirror typeMirror = element.getSuperclass();
if (typeMirror.getKind() == TypeKind.NONE) {
return null;
}
final TypeElement element1 = (TypeElement)typeUtils.asElement(typeMirror);
return value(element1, typeUtils);
}
private static String readDbNameValue(AnnotationMirror mirror) {
final Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = mirror.getElementValues();
final Set<? extends Map.Entry<? extends ExecutableElement, ? extends AnnotationValue>> entries = elementValues.entrySet();
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : entries) {
if ("value".equals(entry.getKey().getSimpleName().toString())) {
return (String) entry.getValue().getValue();
}
}
return null;
}
private static AnnotationMirror findDbNameMirror(TypeElement element) {
final List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
for (AnnotationMirror mirror : mirrors) {
final String name = mirror.getAnnotationType().asElement().toString();
if (Constants.DBNAME.equals(name)) {
return mirror;
}
}
return null;
}
}
@@ -0,0 +1,117 @@
package io.ebean.querybean.generator;
class KotlinLangAdapter implements LangAdapter {
@Override
public void beginClass(Append writer, String shortName) {
writer.append("class Q%s : TQRootBean<%1$s, Q%1$s> {", shortName).eol();
}
@Override
public void beginAssocClass(Append writer, String shortName, String origShortName) {
writer.append("class Q%s<R> : TQAssocBean<%s,R> {", shortName, origShortName).eol();
}
@Override
public void alias(Append writer, String shortName) {
writer.append(" companion object {").eol();
writer.append(" /**").eol();
writer.append(" * shared 'Alias' instance used to provide").eol();
writer.append(" * properties to select and fetch clauses").eol();
writer.append(" */").eol();
writer.append(" val _alias = Q").append(shortName).append("(true)").eol();
writer.eol();
writer.append(" /**").eol();
writer.append(" * Return a query bean used to build a FetchGroup.").eol();
writer.append(" */").eol();
writer.append(" fun forFetchGroup(): Q%s {", shortName).eol();
writer.append(" return Q%s(FetchGroup.queryFor(%s::class.java));", shortName, shortName).eol();
writer.append(" }").eol();
writer.append(" }").eol().eol();
}
@Override
public void assocBeanConstructor(Append writer, String shortName) {
writer.append(" constructor(name: String, root: R) : super(name, root)").eol();
writer.eol();
writer.append(" constructor(name: String, root: R, prefix: String) : super(name, root, prefix)").eol();
}
@Override
public void fetch(Append writer, String origShortName) {
writeAssocBeanFetch(writer, origShortName, "", "Eagerly fetch this association loading the specified properties.");
writeAssocBeanFetch(writer, origShortName, "Query", "Eagerly fetch this association using a 'query join' loading the specified properties.");
writeAssocBeanFetch(writer, origShortName, "Cache", "Eagerly fetch this association using L2 cache.");
writeAssocBeanFetch(writer, origShortName, "Lazy", "Use lazy loading for this association loading the specified properties.");
}
private void writeAssocBeanFetch(Append writer, String origShortName, String fetchType, String comment) {
// fun fetch(vararg properties: TQProperty<QContact>): R {
// return fetchProperties(*properties)
// }
writer.append(" /**").eol();
writer.append(" * ").append(comment).eol();
writer.append(" */").eol();
writer.append(" fun fetch%s(vararg properties: TQProperty<Q%s>) : R {", fetchType, origShortName).eol();
writer.append(" return fetch%sProperties(*properties)", fetchType).eol();
writer.append(" }").eol();
writer.eol();
}
@Override
public void rootBeanConstructor(Append writer, String shortName, String dbName) {
String name = (dbName == null) ? "default" : dbName;
writer.append(" /**").eol();
writer.append(" * Construct using the %s Database.", name).eol();
writer.append(" */").eol();
if (dbName == null) {
writer.append(" constructor() : super(%s::class.java)", shortName).eol().eol();
} else {
writer.append(" constructor() : super(%s::class.java, DB.byName(\"%s\"))", shortName, dbName).eol().eol();
}
writer.append(" /**").eol();
writer.append(" * Construct with a given Transaction.", name).eol();
writer.append(" */").eol();
if (dbName == null) {
writer.append(" constructor(transaction: Transaction) : super(%s::class.java, transaction)", shortName).eol().eol();
} else {
writer.append(" constructor(transaction: Transaction) : super(%s::class.java, DB.byName(\"%s\"), transaction)", shortName, dbName).eol().eol();
}
writer.eol();
writer.append(" /**").eol();
writer.append(" * Construct with a given Database.").eol();
writer.append(" */").eol();
writer.append(" constructor(database: Database) : super(%s::class.java, database)", shortName).eol().eol();
writer.append(" /**").eol();
writer.append(" * Construct for Alias.").eol();
writer.append(" */").eol();
writer.append(" private constructor(dummy: Boolean) : super(dummy)").eol().eol();
writer.append(" /**").eol();
writer.append(" * Private constructor for FetchGroup building.").eol();
writer.append(" */").eol();
writer.append(" private constructor(fetchGroupQuery: Query<%s>) : super(fetchGroupQuery)", shortName).eol();
}
@Override
public void fieldDefn(Append writer, String propertyName, String typeDefn) {
writer.append(" lateinit var %s: ", propertyName);
if (typeDefn.endsWith(",Integer>")) {
typeDefn = typeDefn.replace(",Integer>", ",Int>");
}
writer.append(typeDefn);
}
}
@@ -0,0 +1,19 @@
package io.ebean.querybean.generator;
public interface LangAdapter {
void beginClass(Append writer, String shortName);
void beginAssocClass(Append writer, String shortName, String origShortName);
void alias(Append writer, String shortName);
void rootBeanConstructor(Append writer, String shortName, String dbName);
void assocBeanConstructor(Append writer, String shortName);
void fetch(Append writer, String origShortName);
void fieldDefn(Append writer, String propertyName, String typeDefn);
}
@@ -0,0 +1,21 @@
package io.ebean.querybean.generator;
import java.util.List;
class ModuleMeta {
private final List<String> entities;
private final List<String> other;
ModuleMeta(List<String> entities, List<String> other) {
this.entities = entities;
this.other = other;
}
List<String> getEntities() {
return entities;
}
List<String> getOther() {
return other;
}
}

Some files were not shown because too many files have changed in this diff Show More