mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b073ef10a | ||
|
|
6a7555055d | ||
|
|
eb31f1bfce | ||
|
|
2e4f99318a | ||
|
|
409c1d06b2 | ||
|
|
435e1f61fe | ||
|
|
0230e3e253 | ||
|
|
770364fd1a | ||
|
|
fbc2d70967 | ||
|
|
276e865f72 | ||
|
|
9ded3890d7 | ||
|
|
bfeb0cd667 | ||
|
|
119049b696 | ||
|
|
33ff113585 | ||
|
|
17e0953cad | ||
|
|
e3ca5d2419 | ||
|
|
a5f435dbcf | ||
|
|
aa1e021501 | ||
|
|
7ea6f16207 | ||
|
|
197852857d | ||
|
|
e7e6e00473 | ||
|
|
933c791d33 | ||
|
|
043c523c2a | ||
|
|
82247fd4e4 | ||
|
|
27f86548a6 | ||
|
|
7e8424328f | ||
|
|
923828ce87 | ||
|
|
e195f20981 | ||
|
|
86d0216159 | ||
|
|
a4698ea1b6 | ||
|
|
888384f7db | ||
|
|
817c946eeb | ||
|
|
1749c2cb4c | ||
|
|
3afd3c4530 | ||
|
|
e5f98f1b7a | ||
|
|
2e496c9e1e | ||
|
|
5975694538 | ||
|
|
03a42f7f6e | ||
|
|
84f1e05eb4 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.34.3</version>
|
||||
<version>11.36.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.34.3</tag>
|
||||
<tag>ebean-11.36.2</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -117,7 +117,13 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>4.5</version>
|
||||
<version>4.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-types</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -387,7 +393,7 @@
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:io.ebeanservice:io.ebean.common:io.ebean.bean:io.ebean.service:io.ebean.metric:io.ebean.util:io.ebean.config.properties:io.ebean.config.dbplatform*</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
|
||||
@@ -15,8 +15,8 @@ import java.util.Optional;
|
||||
* public class CustomerFinder extends BeanFinder<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerFinder(EbeanServer server) {
|
||||
* super(Customer.class, server);
|
||||
* public CustomerFinder(Database database) {
|
||||
* super(Customer.class, database);
|
||||
* }
|
||||
*
|
||||
* // ... add customer specific finders
|
||||
@@ -29,25 +29,25 @@ import java.util.Optional;
|
||||
*/
|
||||
public abstract class BeanFinder<I,T> {
|
||||
|
||||
protected final EbeanServer server;
|
||||
protected final Database server;
|
||||
|
||||
protected final Class<T> type;
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
* Create with the given bean type and Database instance.
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent.
|
||||
* @param server The Database instance typically created via Spring factory or equivalent.
|
||||
*/
|
||||
protected BeanFinder(Class<T> type, EbeanServer server) {
|
||||
protected BeanFinder(Class<T> type, Database server) {
|
||||
this.type = type;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the EbeanServer to use.
|
||||
* Return the Database to use.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
public Database db() {
|
||||
return server;
|
||||
}
|
||||
|
||||
@@ -66,21 +66,20 @@ public abstract class BeanFinder<I,T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* Return typically a different Database to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
* This is equivalent to {@link DB#byName(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
* @param server The name of the Database. If this is null then the default Database is returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
public Database db(String server) {
|
||||
return DB.byName(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
* Equivalent to {@link Database#getReference(Class, Object)}
|
||||
*/
|
||||
@Nonnull
|
||||
public T ref(I id) {
|
||||
@@ -89,8 +88,6 @@ public abstract class BeanFinder<I,T> {
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T findById(I id) {
|
||||
@@ -107,8 +104,6 @@ public abstract class BeanFinder<I,T> {
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
@@ -138,7 +133,7 @@ public abstract class BeanFinder<I,T> {
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#update(Class)}
|
||||
* Equivalent to {@link Database#update(Class)}
|
||||
*/
|
||||
protected UpdateQuery<T> updateQuery() {
|
||||
return db().update(type);
|
||||
@@ -147,7 +142,7 @@ public abstract class BeanFinder<I,T> {
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
* Equivalent to {@link Database#find(Class)}
|
||||
*/
|
||||
protected Query<T> query() {
|
||||
return db().find(type);
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.Collection;
|
||||
* public class CustomerRepository extends BeanRepository<Long,Customer> {
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* public CustomerRepository(Database server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
@@ -34,23 +34,23 @@ import java.util.Collection;
|
||||
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the given bean type and EbeanServer instance.
|
||||
* Create with the given bean type and Database instance.
|
||||
* <p>
|
||||
* Typically users would extend BeanRepository rather than BeanFinder.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Inject
|
||||
* public CustomerRepository(EbeanServer server) {
|
||||
* public CustomerRepository(Database server) {
|
||||
* super(Customer.class, server);
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param type The bean type
|
||||
* @param server The EbeanServer instance typically created via Spring factory or equivalent
|
||||
* @param server The Database instance typically created via Spring factory or equivalent
|
||||
*/
|
||||
protected BeanRepository(Class<T> type, EbeanServer server) {
|
||||
protected BeanRepository(Class<T> type, Database server) {
|
||||
super(type, server);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
* @see Database#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty(T bean) {
|
||||
db().markAsDirty(bean);
|
||||
@@ -111,7 +111,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
* @see Database#save(Object)
|
||||
*/
|
||||
public void save(T bean) {
|
||||
db().save(bean);
|
||||
@@ -127,7 +127,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
* @see Database#update(Object)
|
||||
*/
|
||||
public void update(T bean) {
|
||||
db().update(bean);
|
||||
@@ -136,7 +136,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
* @see Database#insert(Object)
|
||||
*/
|
||||
public void insert(T bean) {
|
||||
db().insert(bean);
|
||||
@@ -157,7 +157,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
* @see Database#delete(Object)
|
||||
*/
|
||||
public boolean delete(T bean) {
|
||||
return db().delete(bean);
|
||||
@@ -177,7 +177,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
* @see Database#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent(T bean) {
|
||||
return db().deletePermanent(bean);
|
||||
@@ -189,7 +189,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object)
|
||||
* @see Database#merge(Object)
|
||||
*/
|
||||
public void merge(T bean) {
|
||||
db().merge(bean);
|
||||
@@ -201,7 +201,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#merge(Object, MergeOptions)
|
||||
* @see Database#merge(Object, MergeOptions)
|
||||
*/
|
||||
public void merge(T bean, MergeOptions options) {
|
||||
db().merge(bean, options);
|
||||
@@ -210,7 +210,7 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
* @see Database#refresh(Object)
|
||||
*/
|
||||
public void refresh(T bean) {
|
||||
db().refresh(bean);
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package io.ebean;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Provides access to the internal state of an entity bean.
|
||||
*/
|
||||
@@ -58,7 +57,7 @@ public interface BeanState {
|
||||
*
|
||||
* // set loaded state on the email property to false so that
|
||||
* // the email property is not included in a stateless update
|
||||
* Ebean.getBeanState(user).setPropertyLoaded("email", false);
|
||||
* DB.getBeanState(user).setPropertyLoaded("email", false);
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
@@ -103,7 +102,7 @@ public interface BeanState {
|
||||
/**
|
||||
* Advanced - Used to programmatically build a partially or fully loaded
|
||||
* entity bean. First create an entity bean via
|
||||
* {@link EbeanServer#createEntityBean(Class)}, then populate its properties
|
||||
* {@link Database#createEntityBean(Class)}, then populate its properties
|
||||
* and then call this method specifying which properties where loaded or null
|
||||
* for a fully loaded entity bean.
|
||||
*/
|
||||
|
||||
@@ -17,11 +17,11 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "{call sp_order_mod(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* CallableSql cs = DB.createCallableSql(sql);
|
||||
* cs.setParameter(1, "turbo");
|
||||
* cs.registerOut(2, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(2);
|
||||
@@ -38,7 +38,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "{call sp_insert_order(?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* CallableSql cs = DB.createCallableSql(sql);
|
||||
*
|
||||
* // Inform Ebean this stored procedure inserts into the
|
||||
* // oe_order table and inserts + updates the oe_order_detail table.
|
||||
@@ -46,35 +46,33 @@ import java.sql.SQLException;
|
||||
* cs.addModification("oe_order", true, false, false);
|
||||
* cs.addModification("oe_order_detail", true, true, false);
|
||||
*
|
||||
* Transaction t = Ebean.startTransaction();
|
||||
*
|
||||
* // execute using JDBC batching 10 statements at a time
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(10);
|
||||
* try {
|
||||
* try (Transaction t = DB.beginTransaction()) {
|
||||
*
|
||||
* // execute using JDBC batching 10 statements at a time
|
||||
* t.setBatchMode(true);
|
||||
* t.setBatchSize(10);
|
||||
*
|
||||
* cs.setParameter(1, "Was");
|
||||
* cs.setParameter(2, "Banana");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "Here");
|
||||
* cs.setParameter(2, "Kumera");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* cs.setParameter(1, "More");
|
||||
* cs.setParameter(2, "Apple");
|
||||
* Ebean.execute(cs);
|
||||
* DB.execute(cs);
|
||||
*
|
||||
* // Ebean.externalModification("oe_order",true,false,false);
|
||||
* // Ebean.externalModification("oe_order_detail",true,true,false);
|
||||
* Ebean.commitTransaction();
|
||||
* // DB.externalModification("oe_order",true,false,false);
|
||||
* // DB.externalModification("oe_order_detail",true,true,false);
|
||||
* t.commit();
|
||||
*
|
||||
* } finally {
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @see SqlUpdate
|
||||
* @see Ebean#execute(CallableSql)
|
||||
*/
|
||||
public interface CallableSql {
|
||||
|
||||
@@ -173,7 +171,7 @@ public interface CallableSql {
|
||||
* Add table modification information to the TransactionEvent.
|
||||
* <p>
|
||||
* This would be similar to using the
|
||||
* <code>Ebean.externalModification()</code> method. It may be easier and make
|
||||
* <code>DB.externalModification()</code> method. It may be easier and make
|
||||
* more sense to set it here with the CallableSql.
|
||||
* </p>
|
||||
* <p>
|
||||
|
||||
@@ -17,8 +17,58 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* DB is a registry of {@link Database} by name.
|
||||
* <p>
|
||||
* DB additionally provides a convenient way to use the 'default' Database.
|
||||
* <p>
|
||||
* <h3>Default database</h3>
|
||||
* <p>
|
||||
* One of the Database instances can be registered as the "default database"
|
||||
* and can be obtained using <code>DB.getDefault()</code>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Database database = DB.getDefault();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Named database</h3>
|
||||
* <p>
|
||||
* Multiple database instances can be registered with DB and we can obtain them
|
||||
* using <code>DB.byName()</code>
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Database hrDatabase = DB.byName("hr");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Convenience methods</h3>
|
||||
* <p>
|
||||
* DB has methods like {@link #find(Class)} and {@link #save(Object)} which are
|
||||
* just convenience for using the default database.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch using the default database
|
||||
* Order order = DB.find(Order.class, 10);
|
||||
*
|
||||
* // is the same as
|
||||
* Database database = DB.getDefault();
|
||||
* Order order = database.find(Order.class, 10);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public class DB {
|
||||
|
||||
/**
|
||||
* Hide constructor.
|
||||
*/
|
||||
private DB() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default database.
|
||||
*/
|
||||
@@ -106,22 +156,21 @@ public class DB {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* try (Transaction txn = DB.beginTransaction()) {
|
||||
* Order order = DB.find(Order.class,10); ...
|
||||
* try (Transaction transaction = DB.beginTransaction()) {
|
||||
*
|
||||
* DB.save(order);
|
||||
* Order order = DB.find(Order.class, 42);
|
||||
* order.setStatus(Status.COMPLETE);
|
||||
* order.save();
|
||||
*
|
||||
* txn.commit();
|
||||
* transaction.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* If you want to externalise the transaction management then you should be
|
||||
* able to do this via Database. Specifically with Database you can pass
|
||||
* the transaction to the various find() and save() execute() methods. This
|
||||
* gives you the ability to create the transactions yourself externally from
|
||||
* Ebean and pass those transactions through to the various methods available
|
||||
* on Database.
|
||||
* If we want to externalise the transaction management then we do this via Database.
|
||||
* With Database we can pass the transaction to the various find(), save() and execute()
|
||||
* methods. This gives us the ability to create the transactions externally from Ebean
|
||||
* and use the transaction explicitly via the various methods available on Database.
|
||||
* </p>
|
||||
*/
|
||||
public static Transaction beginTransaction() {
|
||||
@@ -150,29 +199,24 @@ public class DB {
|
||||
* // suspend it until this transaction ends
|
||||
*
|
||||
* try (Transaction txn = DB.beginTransaction(TxScope.requiresNew())) {
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* // commit the transaction
|
||||
* txn.commit();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>REQUIRED example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // start a new transaction if there is not a current transaction
|
||||
*
|
||||
* try (Transaction txn = DB.beginTransaction(TxScope.required())) {
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* // commit the transaction if it was created or
|
||||
* // do nothing if there was already a current transaction
|
||||
* txn.commit();
|
||||
*
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static Transaction beginTransaction(TxScope scope) {
|
||||
@@ -291,18 +335,6 @@ public class DB {
|
||||
* OneToMany, OneToOne or ManyToMany annotation.
|
||||
* </p>
|
||||
* <p>
|
||||
* In this example below the details property has a CascadeType.ALL set so
|
||||
* saving an order will also save all its details.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When a save cascades via a OneToMany or ManyToMany Ebean will automatically
|
||||
* set the 'parent' object to the 'detail' object. In the example below in
|
||||
* saving the order and cascade saving the order details the 'parent' order
|
||||
@@ -1043,15 +1075,15 @@ public class DB {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* DB.execute(scope, new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* });
|
||||
* DB.execute(scope, new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -1067,19 +1099,17 @@ public class DB {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.execute(() -> {
|
||||
* DB.execute(() -> {
|
||||
*
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* User u2 = DB.find(User.class, 2);
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* User u2 = DB.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* DB.save(u1);
|
||||
* DB.save(u2);
|
||||
*
|
||||
* });
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* DB.save(u1);
|
||||
* DB.save(u2);
|
||||
* });
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(Runnable r) {
|
||||
@@ -1094,17 +1124,16 @@ public class DB {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* DB.executeCall(scope, new Callable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* DB.executeCall(scope, new Callable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T executeCall(TxScope scope, Callable<T> c) {
|
||||
@@ -1123,21 +1152,19 @@ public class DB {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.executeCall(() -> {
|
||||
* DB.executeCall(() -> {
|
||||
*
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* User u2 = DB.find(User.class, 2);
|
||||
* User u1 = DB.find(User.class, 1);
|
||||
* User u2 = DB.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* DB.save(u1);
|
||||
* DB.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
*
|
||||
* });
|
||||
* DB.save(u1);
|
||||
* DB.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* });
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T executeCall(Callable<T> c) {
|
||||
@@ -1175,7 +1202,6 @@ public class DB {
|
||||
* @param deletes true if rows on the table where deleted
|
||||
*/
|
||||
public static void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
|
||||
|
||||
getDefault().externalModification(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class DatabaseFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown gracefully all EbeanServers cleaning up any resources as required.
|
||||
* Shutdown gracefully all Database instances cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.function.Predicate;
|
||||
* String sql = "select id, name from customer where name like :name and status_code = :status";
|
||||
*
|
||||
* List<CustomerDto> beans =
|
||||
* Ebean.findDto(CustomerDto.class, sql)
|
||||
* DB.findDto(CustomerDto.class, sql)
|
||||
* .setParameter("name", "Acme%")
|
||||
* .setParameter("status", "ACTIVE")
|
||||
* .findList();
|
||||
|
||||
@@ -24,97 +24,11 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This Ebean object is effectively a singleton that holds a map of registered
|
||||
* {@link EbeanServer}s. It additionally provides a convenient way to use the
|
||||
* 'default' EbeanServer.
|
||||
* Ebean is a registry of {@link Database} by name. Ebean has now been renamed to {@link DB}.
|
||||
* <p>
|
||||
* If you are using a Dependency Injection framework such as
|
||||
* <strong>Spring</strong> or <strong>Guice</strong> you will probably
|
||||
* <strong>NOT</strong> use this Ebean singleton object. Instead you will
|
||||
* configure and construct EbeanServer instances using {@link ServerConfig} and
|
||||
* {@link EbeanServerFactory} and inject those EbeanServer instances into your
|
||||
* data access objects.
|
||||
* </p>
|
||||
* Ebean is effectively this is an alias for {@link DB} which is the new and improved name for Ebean.
|
||||
* <p>
|
||||
* In documentation "Ebean singleton" refers to this object.
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>There is one EbeanServer per Database (javax.sql.DataSource).</li>
|
||||
* <li>EbeanServers can be 'registered' with the Ebean singleton (put into its
|
||||
* map). Registered EbeanServer's can later be retrieved via
|
||||
* {@link #getServer(String)}.</li>
|
||||
* <li>One EbeanServer can be referred to as the 'default' EbeanServer. For
|
||||
* convenience, the Ebean singleton (this object) provides methods such as
|
||||
* {@link #find(Class)} that proxy through to the 'default' EbeanServer. This
|
||||
* can be useful for applications that use a single database.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* For developer convenience Ebean has static methods that proxy through to the
|
||||
* methods on the <em>'default'</em> EbeanServer. These methods are provided for
|
||||
* developers who are mostly using a single database. Many developers will be
|
||||
* able to use the methods on Ebean rather than get a EbeanServer.
|
||||
* </p>
|
||||
* <p>
|
||||
* EbeanServers can be created and used without ever needing or using the Ebean
|
||||
* singleton. Refer to {@link ServerConfig#setRegister(boolean)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can either programmatically create/register EbeanServers via
|
||||
* {@link EbeanServerFactory} or they can automatically be created and
|
||||
* registered when you first use the Ebean singleton. When EbeanServers are
|
||||
* created automatically they are configured using information in the
|
||||
* ebean.properties file.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When you have multiple databases and need access to a specific one the
|
||||
* {@link #getServer(String)} method provides access to the EbeanServer for that
|
||||
* specific database.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
*
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
*
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
*
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
*
|
||||
* }</pre>
|
||||
* The preference is to use DB and Database rather than Ebean and EbeanServer.
|
||||
*/
|
||||
public final class Ebean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
|
||||
@@ -124,13 +38,12 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages creation and cache of EbeanServers.
|
||||
* Manages creation and cache of Databases.
|
||||
*/
|
||||
private static final Ebean.ServerManager serverMgr = new Ebean.ServerManager();
|
||||
|
||||
/**
|
||||
* Helper class for managing fast and safe access and creation of
|
||||
* EbeanServers.
|
||||
* Helper class for managing fast and safe access and creation of Databases.
|
||||
*/
|
||||
private static final class ServerManager {
|
||||
|
||||
@@ -147,7 +60,7 @@ public final class Ebean {
|
||||
private final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* The 'default' EbeanServer.
|
||||
* The 'default' Database.
|
||||
*/
|
||||
private EbeanServer defaultServer;
|
||||
|
||||
@@ -166,20 +79,20 @@ public final class Ebean {
|
||||
throw e;
|
||||
|
||||
} catch (DataSourceConfigurationException e) {
|
||||
String msg = "Configuration error creating DataSource for the default EbeanServer." +
|
||||
String msg = "Configuration error creating DataSource for the default Database." +
|
||||
" This typically means a missing application-test.yaml or missing ebean-test-config dependency." +
|
||||
" See https://ebean.io/docs/trouble-shooting#datasource";
|
||||
throw new DataSourceConfigurationException(msg, e);
|
||||
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error trying to create the default EbeanServer", e);
|
||||
logger.error("Error trying to create the default Database", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private EbeanServer getDefaultServer() {
|
||||
if (defaultServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
String msg = "The default Database has not been defined?";
|
||||
msg += " This is normally set via the ebean.datasource.default property.";
|
||||
msg += " Otherwise it should be registered programmatically via registerServer()";
|
||||
throw new PersistenceException(msg);
|
||||
@@ -201,7 +114,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronized read, create and put of EbeanServers.
|
||||
* Synchronized read, create and put of Databases.
|
||||
*/
|
||||
private EbeanServer getWithCreate(String name) {
|
||||
|
||||
@@ -240,7 +153,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EbeanServer for a given DataSource. If name is null this will
|
||||
* Get the Database for a given DataSource. If name is null this will
|
||||
* return the 'default' EbeanServer.
|
||||
* <p>
|
||||
* This is provided to access EbeanServer for databases other than the
|
||||
@@ -631,7 +544,8 @@ public final class Ebean {
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* DB.update(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1131,10 +1045,9 @@ public final class Ebean {
|
||||
*
|
||||
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
|
||||
*
|
||||
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
|
||||
* query.setParameter(1, "Rob%");
|
||||
*
|
||||
* List<Customer> customers = query.findList();
|
||||
* List<Customer> customers = DB.findNative(Customer.class, sql)
|
||||
* .setParameter(1, "Rob%")
|
||||
* .findList()
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
|
||||
@@ -22,8 +22,8 @@ package io.ebean;
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* List<Customer> list =
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
@@ -46,7 +46,7 @@ package io.ebean;
|
||||
* .includeZeros();
|
||||
*
|
||||
* List<Customer> list =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .add(qbe)
|
||||
* .findList();
|
||||
|
||||
@@ -13,27 +13,15 @@ import java.util.Map;
|
||||
* {@link Query#where()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This provides a convenient way to create expressions for the 'Default'
|
||||
* server. It is actually a short cut for using the ExpressionFactory of the
|
||||
* 'default' EbeanServer.
|
||||
* This provides a convenient way to create expressions for the default
|
||||
* database.
|
||||
* <p>
|
||||
* See also {@link Ebean#getExpressionFactory()}
|
||||
* See also {@link DB#getExpressionFactory()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Creates standard common expressions for using in a Query Where or Having
|
||||
* clause.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Example: Using an Expr.or() method
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where(
|
||||
* Expr.or(Expr.eq("status", Order.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
* @see Query#where()
|
||||
*/
|
||||
@@ -250,6 +238,43 @@ public class Expr {
|
||||
return Ebean.getExpressionFactory().in(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return Ebean.getExpressionFactory().inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Id Equal to - ID property is equal to the value.
|
||||
*/
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.Map;
|
||||
* Expr.or(Expr.eq("status", Order.Status.NEW),
|
||||
* Expr.gt("orderDate", lastWeek));
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.where().add(newOrLastWeek);
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .where().add(newOrLastWeek)
|
||||
* .findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
*
|
||||
@@ -325,6 +325,41 @@ public interface ExpressionFactory {
|
||||
*/
|
||||
Expression in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Expression inOrEmpty(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Not In - property has a value in the array of values.
|
||||
*/
|
||||
|
||||
@@ -321,7 +321,7 @@ public interface ExpressionList<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
@@ -332,7 +332,7 @@ public interface ExpressionList<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -352,7 +352,7 @@ public interface ExpressionList<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* String name =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .where().eq("id", 42)
|
||||
* .findSingleAttribute();
|
||||
@@ -435,7 +435,7 @@ public interface ExpressionList<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -502,7 +502,7 @@ public interface ExpressionList<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name") // only select the customer name
|
||||
* .findList();
|
||||
@@ -575,7 +575,7 @@ public interface ExpressionList<T> {
|
||||
*
|
||||
* List<CountedValue<Order.Status>> orderStatusCount =
|
||||
*
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status")
|
||||
* .where()
|
||||
* .gt("orderDate", LocalDate.now().minusMonths(3))
|
||||
@@ -758,20 +758,6 @@ public interface ExpressionList<T> {
|
||||
|
||||
/**
|
||||
* Add an Expression to the list.
|
||||
* <p>
|
||||
* This returns the list so that add() can be chained.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = Ebean.find(Customer.class);
|
||||
* query.where()
|
||||
* .like("name","Rob%")
|
||||
* .eq("status", Customer.ACTIVE);
|
||||
*
|
||||
* List<Customer> list = query.findList();
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> add(Expression expr);
|
||||
|
||||
@@ -907,11 +893,10 @@ public interface ExpressionList<T> {
|
||||
* example.setName("Rob%");
|
||||
* example.setNotes("%something%");
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where()
|
||||
* // pass the bean into the where() clause
|
||||
* .exampleLike(example)
|
||||
* // you can add other expressions to the same query
|
||||
* .gt("id", 2).findList();
|
||||
* List<Customer> list =
|
||||
* DB.find(Customer.class)
|
||||
* .where().exampleLike(example)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -926,7 +911,7 @@ public interface ExpressionList<T> {
|
||||
* // create a ExampleExpression with more control
|
||||
* ExampleExpression qbe = new ExampleExpression(example, true, LikeType.EQUAL_TO).includeZeros();
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).where().add(qbe).findList();
|
||||
* List<Customer> list = DB.find(Customer.class).where().add(qbe).findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -1003,6 +988,41 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> in(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* if (ids != null && !ids.isEmpty()) {
|
||||
* query.where().in("customer.id", ids);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .inOrEmpty("customer.id", ids)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values);
|
||||
|
||||
/**
|
||||
* In - using a subQuery.
|
||||
* <p>
|
||||
@@ -1247,6 +1267,68 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
ExpressionList<T> raw(String raw);
|
||||
|
||||
/**
|
||||
* Only add the raw expression if the values is not null or empty.
|
||||
* <p>
|
||||
* This is a pure convenience expression to make it nicer to deal with the pattern where we use
|
||||
* raw() expression with a subquery and only want to add the subquery predicate when the collection
|
||||
* of values is not empty.
|
||||
* </p>
|
||||
* <h3>Without inOrEmpty()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where() // add some predicates
|
||||
* .eq("status", Status.NEW);
|
||||
*
|
||||
* // common pattern - we can use rawOrEmpty() instead
|
||||
* if (orderIds != null && !orderIds.isEmpty()) {
|
||||
* query.where().raw("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* }
|
||||
*
|
||||
* query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Using rawOrEmpty()</h3>
|
||||
* Note that in the example below we use the <code>?1</code> bind parameter to get "parameter expansion"
|
||||
* for each element in the collection.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* // only add the expression if orderIds is not empty
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id in (?1))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <h3>Postgres ANY</h3>
|
||||
* With Postgres we would often use the SQL <code>ANY</code> expression and array parameter binding
|
||||
* rather than <code>IN</code>.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* query.where()
|
||||
* .eq("status", Status.NEW)
|
||||
* .rawOrEmpty("t0.customer_id in (select o.customer_id from orders o where o.id = any(?))", orderIds);
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that we need to cast the Postgres array for UUID types like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* " ... = any(?::uuid[])"
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param raw The raw expression that is typically a subquery
|
||||
* @param values The values which is typically a list or set of id values.
|
||||
*/
|
||||
ExpressionList<T> rawOrEmpty(String raw, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Add a match expression.
|
||||
*
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* The extended API for EbeanServer.
|
||||
* The extended API for Database.
|
||||
* <p>
|
||||
* This provides the finder methods that take an explicit transaction rather than obtaining
|
||||
* the transaction from the usual mechanism (which is ThreadLocal based).
|
||||
@@ -26,7 +26,7 @@ import java.util.function.Predicate;
|
||||
* the transaction to use.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that in all cases the transaction supplied can be null and in this case the EbeanServer
|
||||
* Note that in all cases the transaction supplied can be null and in this case the Database
|
||||
* will use the normal mechanism to obtain the transaction to use.
|
||||
* </p>
|
||||
*/
|
||||
@@ -121,7 +121,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEach((Order order) -> {
|
||||
@@ -155,7 +155,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEachWhile((Order order) -> {
|
||||
@@ -194,8 +194,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findList();
|
||||
*
|
||||
@@ -272,7 +271,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -301,8 +300,7 @@ public interface ExtendedServer {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Set<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findSet();
|
||||
*
|
||||
@@ -341,7 +339,7 @@ public interface ExtendedServer {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
@@ -351,7 +349,7 @@ public interface ExtendedServer {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -413,7 +411,7 @@ public interface ExtendedServer {
|
||||
/**
|
||||
* Execute the update query returning the number of rows updated.
|
||||
* <p>
|
||||
* The update query must be created using {@link EbeanServer#update(Class)}.
|
||||
* The update query must be created using {@link Database#update(Class)}.
|
||||
* </p>
|
||||
*
|
||||
* @param query the update query to execute
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.Serializable;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
* List<Order> list = DB.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
@@ -36,7 +36,7 @@ import java.io.Serializable;
|
||||
*
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
@@ -52,7 +52,7 @@ import java.io.Serializable;
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
@@ -70,7 +70,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
@@ -100,7 +100,7 @@ import java.io.Serializable;
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
@@ -121,7 +121,7 @@ import java.io.Serializable;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
|
||||
@@ -25,14 +25,14 @@ import java.util.Set;
|
||||
* // get a list of entities (query execution statistics in this case)
|
||||
*
|
||||
* List<MetaQueryStatistic> list =
|
||||
* Ebean.find(MetaQueryStatistic.class).findList();
|
||||
* DB.find(MetaQueryStatistic.class).findList();
|
||||
*
|
||||
* long nowMinus24Hrs = System.currentTimeMillis() - 24 * (1000 * 60 * 60);
|
||||
*
|
||||
* // sort and filter the list returning a filtered list...
|
||||
*
|
||||
* List<MetaQueryStatistic> filteredList =
|
||||
* Ebean.filter(MetaQueryStatistic.class)
|
||||
* DB.filter(MetaQueryStatistic.class)
|
||||
* .sort("avgTimeMicros desc")
|
||||
* .gt("executionCount", 0)
|
||||
* .gt("lastQueryTime", nowMinus24Hrs)
|
||||
@@ -63,12 +63,12 @@ import java.util.Set;
|
||||
* // get a list of entities (query execution statistics)
|
||||
*
|
||||
* List<Order> orders =
|
||||
* Ebean.find(Order.class).findList();
|
||||
* DB.find(Order.class).findList();
|
||||
*
|
||||
* // Apply a filter...
|
||||
*
|
||||
* List<Order> filteredOrders =
|
||||
* Ebean.filter(Order.class)
|
||||
* DB.filter(Order.class)
|
||||
* .startsWith("customer.name", "Rob")
|
||||
* .eq("customer.shippingAddress.city", "Auckland")
|
||||
* .filter(orders);
|
||||
|
||||
@@ -13,8 +13,7 @@ import java.util.List;
|
||||
* </p>
|
||||
* <h3>Testing</h3>
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation
|
||||
* <p>
|
||||
* For testing the mocki-ebean project has the ability to replace the finder implementation.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
@@ -24,7 +23,7 @@ import java.util.List;
|
||||
* super(Customer.class);
|
||||
* }
|
||||
*
|
||||
* // Add your customer finder methods ...
|
||||
* // Add finder methods ...
|
||||
*
|
||||
* public Customer byName(String name) {
|
||||
* return query().eq("name", name).findOne();
|
||||
@@ -45,6 +44,15 @@ import java.util.List;
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* When the Finder is registered as a field on Customer it can then be used like:
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer rob = Customer.find.byName("Rob");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public class Finder<I, T> {
|
||||
|
||||
@@ -54,9 +62,9 @@ public class Finder<I, T> {
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
* The name of the database this finder will use, null for the default database.
|
||||
*/
|
||||
private final String serverName;
|
||||
private final String _$dbName;
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
@@ -81,15 +89,15 @@ public class Finder<I, T> {
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = null;
|
||||
this._$dbName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
* Create with the type of the entity bean and specific database name.
|
||||
*/
|
||||
public Finder(Class<T> type, String serverName) {
|
||||
public Finder(Class<T> type, String databaseName) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
this._$dbName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,12 +115,10 @@ public class Finder<I, T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
* Return the Database this finder will use.
|
||||
*/
|
||||
public Database db() {
|
||||
return DB.byName(serverName);
|
||||
return DB.byName(_$dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,11 +126,10 @@ public class Finder<I, T> {
|
||||
* <p>
|
||||
* This is equivalent to {@link DB#byName(String)}
|
||||
*
|
||||
* @param server The name of the Database. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
* @param databaseName The name of the Database. If this is null then the default database is returned.
|
||||
*/
|
||||
public Database db(String server) {
|
||||
return DB.byName(server);
|
||||
public Database db(String databaseName) {
|
||||
return DB.byName(databaseName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.concurrent.TimeoutException;
|
||||
* <pre>{@code
|
||||
*
|
||||
* // create a query to find all orders
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* Query<Order> query = DB.find(Order.class);
|
||||
*
|
||||
* // execute the query in a background thread
|
||||
* // immediately returning the futureList
|
||||
|
||||
@@ -11,7 +11,7 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* DB.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
@@ -30,7 +30,7 @@ package io.ebean;
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query q =
|
||||
* Ebean.find(Person.class)
|
||||
* DB.find(Person.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .like("name", "Rob%")
|
||||
@@ -50,7 +50,7 @@ package io.ebean;
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* Query<Customer> q =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where()
|
||||
* .or()
|
||||
* .and()
|
||||
|
||||
@@ -11,15 +11,15 @@ import io.ebean.bean.EntityBean;
|
||||
* Ebean users.
|
||||
* <p>
|
||||
* Note that there is a ebean-mocker project that enables you to use Mockito or similar
|
||||
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
|
||||
* tools to still mock out the underlying 'default Database' for testing purposes.
|
||||
* <p>
|
||||
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
|
||||
* or if you believe it 'pollutes' your entity beans.
|
||||
* <p>
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a Database instance
|
||||
* and have that same instance used with this Model and Finder. The way that works is that when the
|
||||
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
|
||||
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* DI container creates the Database instance it can be registered with DB. In this
|
||||
* way the Database instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* that same instance also used to support the Model and Finder active record style.
|
||||
* <p>
|
||||
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
|
||||
|
||||
@@ -24,8 +24,7 @@ import java.util.concurrent.Future;
|
||||
* // We want to find the first 50 new orders
|
||||
* // ... so we don't really need setFirstRow(0)
|
||||
*
|
||||
* PagedList<Order> pagedList
|
||||
* = ebeanServer.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .where().eq("status", Order.Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setFirstRow(0)
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.util.List;
|
||||
* pairs.add("sj2", 1001);
|
||||
* pairs.add("pf3", 1000);
|
||||
*
|
||||
* List<OCachedNatKeyBean3> list = Ebean.find(OCachedNatKeyBean3.class)
|
||||
* List<OCachedNatKeyBean3> list = DB.find(OCachedNatKeyBean3.class)
|
||||
* .where()
|
||||
* .eq("store", "def")
|
||||
* .inPairs(pairs) // IN clause with 'pairs' of values
|
||||
|
||||
@@ -19,10 +19,7 @@ import java.util.function.Predicate;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orderList =
|
||||
* ebeanServer.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* List<Order> orderList = DB.find(Order.class)
|
||||
* .where()
|
||||
* .like("customer.name","rob%")
|
||||
* .gt("orderDate",lastWeek)
|
||||
@@ -38,29 +35,14 @@ import java.util.function.Predicate;
|
||||
* <pre>{@code
|
||||
*
|
||||
* String oql =
|
||||
* +" fetch customer "
|
||||
* +" fetch details "
|
||||
* +" where customer.name like :custName and orderDate > :minOrderDate "
|
||||
* +" order by customer.id, id desc "
|
||||
* +" limit 50 ";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a named query called "with.cust.and.details"
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createNamedQuery(Order.class,"with.cust.and.details");
|
||||
* query.setParameter("custName", "Rob%");
|
||||
* query.setParameter("minOrderDate", lastWeek);
|
||||
*
|
||||
* List<Order> orderList = query.findList();
|
||||
* List<Order> orderList = DB.createQuery(Order.class, oql)
|
||||
* .setParameter("custName", "Rob%")
|
||||
* .setParameter("minOrderDate", lastWeek)
|
||||
* .findList();
|
||||
* ...
|
||||
* }</pre>
|
||||
* <h3>AutoTune</h3>
|
||||
@@ -377,7 +359,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch a bean with JSON content
|
||||
* EBasicJsonList bean= Ebean.find(EBasicJsonList.class)
|
||||
* EBasicJsonList bean= DB.find(EBasicJsonList.class)
|
||||
* .setId(42)
|
||||
* .setAllowLoadErrors() // collect errors into bean state if we have invalid JSON
|
||||
* .findOne();
|
||||
@@ -436,8 +418,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // Only fetch the customer id, name and status.
|
||||
* // This is described as a "Partial Object"
|
||||
* .select("name, status")
|
||||
@@ -465,8 +446,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // query orders...
|
||||
* List<Order> orders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> orders = DB.find(Order.class)
|
||||
* // fetch the customer...
|
||||
* // ... getting the customers name and phone number
|
||||
* .fetch("customer", "name, phoneNumber")
|
||||
@@ -481,8 +461,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email")
|
||||
* .findList();
|
||||
@@ -551,8 +530,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
|
||||
* .findList();
|
||||
@@ -573,8 +551,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // eager fetch the contacts
|
||||
* .fetch("contacts")
|
||||
* .findList();
|
||||
@@ -637,8 +614,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // lazy fetch contacts with a batch size of 100
|
||||
* .fetch("contacts", new FetchConfig().lazy(100))
|
||||
* .findList();
|
||||
@@ -658,7 +634,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
*/
|
||||
@Nonnull
|
||||
@@ -680,12 +656,11 @@ public interface Query<T> {
|
||||
* the jdbc statement and resultSet are closed at the end of the iteration.
|
||||
* </p>
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Query<Customer> query = DB.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
@@ -732,7 +707,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .findEach((Customer customer) -> {
|
||||
@@ -761,7 +736,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ebeanServer.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
@@ -784,12 +759,11 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning the list of objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findList();
|
||||
*
|
||||
@@ -801,12 +775,11 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning the set of objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Set<Customer> customers =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* Set<Customer> customers = DB.find(Customer.class)
|
||||
* .where().ilike("name", "rob%")
|
||||
* .findSet();
|
||||
*
|
||||
@@ -818,7 +791,7 @@ public interface Query<T> {
|
||||
/**
|
||||
* Execute the query returning a map of the objects.
|
||||
* <p>
|
||||
* This query will execute against the EbeanServer that was used to create it.
|
||||
* This query will execute against the Database that was used to create it.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can use setMapKey() so specify the property values to be used as keys
|
||||
@@ -826,8 +799,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Map<String, Product> map =
|
||||
* ebeanServer.find(Product.class)
|
||||
* Map<String, Product> map = DB.find(Product.class)
|
||||
* .setMapKey("sku")
|
||||
* .findMap();
|
||||
*
|
||||
@@ -843,7 +815,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .orderBy().asc("name")
|
||||
* .findSingleAttributeList();
|
||||
@@ -854,7 +826,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<String> names =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .where().eq("status", Customer.Status.NEW)
|
||||
@@ -875,7 +847,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* String name =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .select("name")
|
||||
* .where().eq("id", 42)
|
||||
* .findSingleAttribute();
|
||||
@@ -934,8 +906,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // assuming the sku of products is unique...
|
||||
* Product product =
|
||||
* ebeanServer.find(Product.class)
|
||||
* Product product = DB.find(Product.class)
|
||||
* .where().eq("sku", "aa113")
|
||||
* .findOne();
|
||||
* ...
|
||||
@@ -947,8 +918,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Fetch order 1 and additionally fetch join its order details...
|
||||
* Order order =
|
||||
* ebeanServer.find(Order.class)
|
||||
* Order order = DB.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findOne();
|
||||
@@ -1089,7 +1059,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* PagedList<Order> pagedList = Ebean.find(Order.class)
|
||||
* PagedList<Order> pagedList = DB.find(Order.class)
|
||||
* .setFirstRow(50)
|
||||
* .setMaxRows(20)
|
||||
* .findPagedList();
|
||||
@@ -1114,11 +1084,9 @@ public interface Query<T> {
|
||||
* // a query with a named parameter
|
||||
* String oql = "find order where status = :orderStatus";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.find(Order.class, oql);
|
||||
*
|
||||
* // bind the named parameter
|
||||
* query.bind("orderStatus", OrderStatus.NEW);
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.find(Order.class, oql)
|
||||
* .setParameter("orderStatus", OrderStatus.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1136,12 +1104,9 @@ public interface Query<T> {
|
||||
* // a query with a positioned parameter
|
||||
* String oql = "where status = ? order by id desc";
|
||||
*
|
||||
* Query<Order> query = ebeanServer.createQuery(Order.class, oql);
|
||||
*
|
||||
* // bind the parameter
|
||||
* query.setParameter(1, OrderStatus.NEW);
|
||||
*
|
||||
* List<Order> list = query.findList();
|
||||
* List<Order> list = DB.createQuery(Order.class, oql)
|
||||
* .setParameter(1, OrderStatus.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -1158,8 +1123,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Order order =
|
||||
* ebeanServer.find(Order.class)
|
||||
* Order order = DB.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("details")
|
||||
* .findOne();
|
||||
@@ -1180,8 +1144,7 @@ public interface Query<T> {
|
||||
* Add a single Expression to the where clause returning the query.
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> newOrders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> newOrders = DB.find(Order.class)
|
||||
* .where().eq("status", Order.NEW)
|
||||
* .findList();
|
||||
* ...
|
||||
@@ -1196,8 +1159,7 @@ public interface Query<T> {
|
||||
* where clause.
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> orders =
|
||||
* ebeanServer.find(Order.class)
|
||||
* List<Order> orders = DB.find(Order.class)
|
||||
* .where()
|
||||
* .eq("status", Order.NEW)
|
||||
* .ilike("customer.name","rob%")
|
||||
@@ -1243,10 +1205,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> list =
|
||||
* ebeanServer.find(Customer.class)
|
||||
* // .fetch("orders", new FetchConfig().lazy())
|
||||
* // .fetch("orders", new FetchConfig().query())
|
||||
* List<Customer> list = DB.find(Customer.class)
|
||||
* .fetch("orders")
|
||||
* .where().ilike("name", "rob%")
|
||||
* .filterMany("orders").eq("status", Order.Status.NEW).gt("orderDate", lastWeek)
|
||||
@@ -1260,8 +1219,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
*
|
||||
* @param propertyName the name of the many property that you want to have a filter on.
|
||||
* @return the expression list that you add filter expressions for the many
|
||||
* to.
|
||||
* @return the expression list that you add filter expressions for the many to.
|
||||
*/
|
||||
ExpressionList<T> filterMany(String propertyName);
|
||||
|
||||
@@ -1375,7 +1333,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Ebean.find(Customer.class)
|
||||
* DB.find(Customer.class)
|
||||
* .setDistinct(true)
|
||||
* .select("name")
|
||||
* .findList();
|
||||
@@ -1391,7 +1349,7 @@ public interface Query<T> {
|
||||
*
|
||||
* List<CountedValue<Order.Status>> orderStatusCount =
|
||||
*
|
||||
* Ebean.find(Order.class)
|
||||
* DB.find(Order.class)
|
||||
* .select("status")
|
||||
* .where()
|
||||
* .gt("orderDate", LocalDate.now().minusMonths(3))
|
||||
@@ -1447,10 +1405,8 @@ public interface Query<T> {
|
||||
*
|
||||
* // Assuming sku is unique for products...
|
||||
*
|
||||
* Map<String,Product> productMap =
|
||||
* ebeanServer.find(Product.class)
|
||||
* // use sku for keys...
|
||||
* .setMapKey("sku")
|
||||
* Map<String,Product> productMap = DB.find(Product.class)
|
||||
* .setMapKey("sku") // sku map keys...
|
||||
* .findMap();
|
||||
*
|
||||
* }</pre>
|
||||
|
||||
@@ -87,7 +87,7 @@ package io.ebean;
|
||||
* // .columnMapping("sum(d.order_qty*d.unit_price)", "totalAmount")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> list = Ebean.find(OrderAggregate.class)
|
||||
* List<OrderAggregate> list = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
@@ -114,7 +114,7 @@ package io.ebean;
|
||||
* .columnMappingIgnore("'ignoreMe'")
|
||||
* .create();
|
||||
*
|
||||
* List<OrderAggregate> orders = Ebean.find(OrderAggregate.class)
|
||||
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order.customer", "name")
|
||||
@@ -146,7 +146,7 @@ package io.ebean;
|
||||
* .tableAliasMapping("p", "details.product")
|
||||
* .create();
|
||||
*
|
||||
* List<Order> ordersFromRaw = Ebean.find(Order.class)
|
||||
* List<Order> ordersFromRaw = DB.find(Order.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .setParameter("maxOrderId", 2)
|
||||
* .setParameter("productId", 1)
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer order by name desc";
|
||||
*
|
||||
* Ebean.createSqlQuery(sql)
|
||||
* DB.sqlQuery(sql)
|
||||
* .findEachRow((resultSet, rowNum) -> {
|
||||
*
|
||||
* // read directly from ResultSet
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.sql.SQLException;
|
||||
*
|
||||
* String sql = "select id, name, status from o_customer where name = ?";
|
||||
*
|
||||
* CustomerDto rob = Ebean.createSqlQuery(sql)
|
||||
* CustomerDto rob = DB.sqlQuery(sql)
|
||||
* .setParameter(1, "Rob")
|
||||
* .findOne(CUSTOMER_MAPPER);
|
||||
*
|
||||
|
||||
@@ -13,20 +13,8 @@ import java.util.Map;
|
||||
* <h3>Example of simple use</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* EbeanServer server = Ebean.getDefaultServer();
|
||||
* server.script().run("/scripts/test-script.sql");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* <h3>Example using place holders in the script</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Map<String,String> placeholders = new HashMap<>();
|
||||
* placeholders.put("tableName", "e_basic");
|
||||
*
|
||||
* EbeanServer server = Ebean.getDefaultServer();
|
||||
* server.script().run("/scripts/test-script.sql");
|
||||
* Database database = DB.getDefault();
|
||||
* database.script().run("/scripts/test-script.sql");
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@@ -45,8 +33,8 @@ public interface ScriptRunner {
|
||||
* Map<String,String> placeholders = new HashMap<>();
|
||||
* placeholders.put("tableName", "e_basic");
|
||||
*
|
||||
* EbeanServer server = Ebean.getDefaultServer();
|
||||
* server.script().run("/scripts/test-script.sql");
|
||||
* Database database = DB.getDefault();
|
||||
* database.script().run("/scripts/test-script.sql", placeholders);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
|
||||
@@ -14,18 +14,17 @@ import java.sql.Connection;
|
||||
public interface Transaction extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Return the current transaction (of the default server) or null if there is
|
||||
* Return the current transaction (of the default database) or null if there is
|
||||
* no current transaction in scope.
|
||||
* <p>
|
||||
* This is the same as <code>Ebean.currentTransaction()</code>
|
||||
* This is the same as <code>DB.currentTransaction()</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* This returns the current transaction for the 'default server'. If you are using
|
||||
* multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}.
|
||||
* This returns the current transaction for the default database.
|
||||
* </p>
|
||||
*
|
||||
* @see Ebean#currentTransaction()
|
||||
* @see EbeanServer#currentTransaction()
|
||||
* @see DB#currentTransaction()
|
||||
* @see Database#currentTransaction()
|
||||
*/
|
||||
static Transaction current() {
|
||||
return Ebean.currentTransaction();
|
||||
@@ -244,7 +243,7 @@ public interface Transaction extends AutoCloseable {
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* try (Transaction transaction = ebeanServer.beginTransaction()) {
|
||||
* try (Transaction transaction = DB.beginTransaction()) {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
@@ -366,13 +365,13 @@ public interface Transaction extends AutoCloseable {
|
||||
* // inserts into a table called sp_test
|
||||
* cs.addModification("sp_test", true, false, false);
|
||||
*
|
||||
* try (Transaction txn = ebeanServer.beginTransaction()) {
|
||||
* try (Transaction txn = DB.beginTransaction()) {
|
||||
* txn.setBatchMode(true);
|
||||
* txn.setBatchSize(10);
|
||||
*
|
||||
* for (int i = 0; i < da.length;) {
|
||||
* cs.setParameter(1, da[i]);
|
||||
* ebeanServer.execute(cs);
|
||||
* DB.execute(cs);
|
||||
* }
|
||||
*
|
||||
* // Note: commit implicitly flushes
|
||||
|
||||
@@ -41,7 +41,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, "incrementPostCount");
|
||||
* Update<Topic> update = DB.createUpdate(Topic.class, "incrementPostCount");
|
||||
* update.setParameter("id", 1);
|
||||
* int rows = update.execute();
|
||||
*
|
||||
|
||||
@@ -12,8 +12,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -39,8 +38,7 @@ package io.ebean;
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -73,8 +71,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .set("status", Customer.Status.ACTIVE)
|
||||
* .set("updtime", new Timestamp(System.currentTimeMillis()))
|
||||
* .where()
|
||||
@@ -93,8 +90,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setNull("notes")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
@@ -114,8 +110,7 @@ public interface UpdateQuery<T> {
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, 'A')")
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
@@ -134,8 +129,7 @@ public interface UpdateQuery<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* int rows = ebeanServer
|
||||
* .update(Customer.class)
|
||||
* int rows = DB.update(Customer.class)
|
||||
* .setRaw("status = coalesce(status, ?)", Customer.Status.ACTIVE)
|
||||
* .where()
|
||||
* .gt("id", 1000)
|
||||
|
||||
@@ -9,7 +9,7 @@ package io.ebean.bean;
|
||||
public interface BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
* Return the name of the associated Database.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ package io.ebean.bean;
|
||||
public interface BeanLoader {
|
||||
|
||||
/**
|
||||
* Return the name of the associated EbeanServer.
|
||||
* Return the name of the associated Database.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
/**
|
||||
* The EbeanServer this is associated with. (used for lazy fetch).
|
||||
* The Database this is associated with. (used for lazy fetch).
|
||||
*/
|
||||
protected transient BeanCollectionLoader loader;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Used to provide some automatic configuration early in the creation of an EbeanServer.
|
||||
* Used to provide some automatic configuration early in the creation of a Database.
|
||||
*/
|
||||
public interface AutoConfigure {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the AutoTune behaviour for a EbeanServer.
|
||||
* Defines the AutoTune behaviour for a Database.
|
||||
*/
|
||||
public class AutoTuneConfig {
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.ebean.config;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Configuration for the container that holds the EbeanServer instances.
|
||||
* Configuration for the container that holds the Database instances.
|
||||
* <p>
|
||||
* Provides configuration for cluster communication (if clustering is used). The cluster communication is
|
||||
* used to invalidate appropriate parts of the L2 cache across the cluster.
|
||||
|
||||
@@ -140,7 +140,7 @@ public class DbMigrationConfig {
|
||||
* <p>
|
||||
* The default of "dbmigration" is reasonable in most cases. You may look to set this
|
||||
* to be something like "dbmigration/myapp" where myapp gives it a unique resource path
|
||||
* in the case there are multiple EbeanServer applications in the single classpath.
|
||||
* in the case there are multiple Database applications in the single classpath.
|
||||
* </p>
|
||||
*/
|
||||
public void setMigrationPath(String migrationPath) {
|
||||
|
||||
@@ -47,6 +47,11 @@ public class PlatformConfig {
|
||||
*/
|
||||
private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
|
||||
|
||||
/**
|
||||
* Set to true to force InetAddress to map to Varchar (for Postgres rather than INET)
|
||||
*/
|
||||
private boolean databaseInetAddressVarchar;
|
||||
|
||||
/**
|
||||
* Modify the default mapping of standard types such as default precision for DECIMAL etc.
|
||||
*/
|
||||
@@ -181,6 +186,20 @@ public class PlatformConfig {
|
||||
this.idType = idType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if InetAddress should map to varchar column (rather than Postgres INET).
|
||||
*/
|
||||
public boolean isDatabaseInetAddressVarchar() {
|
||||
return databaseInetAddressVarchar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to force InetAddress to map to varchar column.
|
||||
*/
|
||||
public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) {
|
||||
this.databaseInetAddressVarchar = databaseInetAddressVarchar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
@@ -235,6 +254,7 @@ public class PlatformConfig {
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
|
||||
|
||||
DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
|
||||
if (dbUuid != null) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
@@ -44,30 +44,30 @@ import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
* The configuration used for creating a Database.
|
||||
* <p>
|
||||
* Used to programmatically construct an EbeanServer and optionally register it
|
||||
* with the Ebean singleton.
|
||||
* Used to programmatically construct a Database and optionally register it
|
||||
* with the DB singleton.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you just use Ebean without this programmatic configuration Ebean will read
|
||||
* the ebean.properties file and take the configuration from there. This usually
|
||||
* If you just use DB without this programmatic configuration DB will read
|
||||
* the application.properties file and take the configuration from there. This usually
|
||||
* includes searching the class path and automatically registering any entity
|
||||
* classes and listeners etc.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* ServerConfig c = new ServerConfig();
|
||||
* ServerConfig config = new ServerConfig();
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
* c.loadFromProperties();
|
||||
* config.loadFromProperties();
|
||||
*
|
||||
* // explicitly register the entity beans to avoid classpath scanning
|
||||
* c.addClass(Customer.class);
|
||||
* c.addClass(User.class);
|
||||
* config.addClass(Customer.class);
|
||||
* config.addClass(User.class);
|
||||
*
|
||||
* EbeanServer server = EbeanServerFactory.create(c);
|
||||
* Database database = DatabaseFactory.create(config);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
@@ -78,12 +78,12 @@ import java.util.ServiceLoader;
|
||||
*
|
||||
* @author emcgreal
|
||||
* @author rbygrave
|
||||
* @see EbeanServerFactory
|
||||
* @see DatabaseFactory
|
||||
*/
|
||||
public class ServerConfig {
|
||||
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
* The Database name.
|
||||
*/
|
||||
private String name = "db";
|
||||
|
||||
@@ -106,12 +106,12 @@ public class ServerConfig {
|
||||
private String resourceDirectory;
|
||||
|
||||
/**
|
||||
* Set to true to register this EbeanServer with the Ebean singleton.
|
||||
* Set to true to register this Database with the DB singleton.
|
||||
*/
|
||||
private boolean register = true;
|
||||
|
||||
/**
|
||||
* Set to true if this is the default/primary server.
|
||||
* Set to true if this is the default/primary database.
|
||||
*/
|
||||
private boolean defaultServer = true;
|
||||
|
||||
@@ -150,7 +150,7 @@ public class ServerConfig {
|
||||
private DocStoreConfig docStoreConfig = new DocStoreConfig();
|
||||
|
||||
/**
|
||||
* Set to true when the EbeanServer only uses Document store.
|
||||
* Set to true when the Database only uses Document store.
|
||||
*/
|
||||
private boolean docStoreOnly;
|
||||
|
||||
@@ -350,7 +350,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Behaviour of updates in JDBC batch to by default include all properties.
|
||||
*/
|
||||
private boolean updateAllPropertiesInBatch = true;
|
||||
private boolean updateAllPropertiesInBatch;
|
||||
|
||||
/**
|
||||
* Default behaviour for updates when cascade save on a O2M or M2M to delete any missing children.
|
||||
@@ -522,7 +522,7 @@ public class ServerConfig {
|
||||
private boolean idGeneratorAutomatic = true;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
* Construct a Database Configuration for programmatically creating an Database.
|
||||
*/
|
||||
public ServerConfig() {
|
||||
|
||||
@@ -693,14 +693,14 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the EbeanServer.
|
||||
* Return the name of the Database.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the EbeanServer.
|
||||
* Set the name of the Database.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
@@ -709,8 +709,8 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
* The container holds all the Database instances and provides clustering communication
|
||||
* services to all the Database instances.
|
||||
*/
|
||||
public ContainerConfig getContainerConfig() {
|
||||
return containerConfig;
|
||||
@@ -719,8 +719,8 @@ public class ServerConfig {
|
||||
/**
|
||||
* Set the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
* The container holds all the Database instances and provides clustering communication
|
||||
* services to all the Database instances.
|
||||
*/
|
||||
public void setContainerConfig(ContainerConfig containerConfig) {
|
||||
this.containerConfig = containerConfig;
|
||||
@@ -760,8 +760,8 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set false if you do not want this EbeanServer to be registered as the "default" server
|
||||
* with the Ebean singleton.
|
||||
* Set false if you do not want this Database to be registered as the "default" database
|
||||
* with the DB singleton.
|
||||
* <p>
|
||||
* This is only used when {@link #setRegister(boolean)} is also true.
|
||||
* </p>
|
||||
@@ -1547,14 +1547,14 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this EbeanServer is a Document store only instance (has no JDBC DB).
|
||||
* Return true if this Database is a Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public boolean isDocStoreOnly() {
|
||||
return docStoreOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this EbeanServer is Document store only instance (has no JDBC DB).
|
||||
* Set to true if this Database is Document store only instance (has no JDBC DB).
|
||||
*/
|
||||
public void setDocStoreOnly(boolean docStoreOnly) {
|
||||
this.docStoreOnly = docStoreOnly;
|
||||
@@ -1954,16 +1954,16 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the EbeanServer instance should be created in offline mode.
|
||||
* Return true if the Database instance should be created in offline mode.
|
||||
*/
|
||||
public boolean isDbOffline() {
|
||||
return dbOffline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the EbeanServer instance should be created in offline mode.
|
||||
* Set to true if the Database instance should be created in offline mode.
|
||||
* <p>
|
||||
* Typically used to create an EbeanServer instance for DDL Migration generation
|
||||
* Typically used to create an Database instance for DDL Migration generation
|
||||
* without requiring a real DataSource / Database to connect to.
|
||||
* </p>
|
||||
*/
|
||||
@@ -2214,7 +2214,7 @@ public class ServerConfig {
|
||||
|
||||
/**
|
||||
* Set to true to disable the class path search even for the case where no entity bean classes
|
||||
* have been registered. This can be used to start an EbeanServer instance just to use the
|
||||
* have been registered. This can be used to start an Database instance just to use the
|
||||
* SQL functions such as SqlQuery, SqlUpdate etc.
|
||||
*/
|
||||
public void setDisableClasspathSearch(boolean disableClasspathSearch) {
|
||||
@@ -2328,8 +2328,7 @@ public class ServerConfig {
|
||||
*
|
||||
* // assume Customer has L2 bean caching enabled ...
|
||||
*
|
||||
* Transaction transaction = Ebean.beginTransaction();
|
||||
* try {
|
||||
* try (Transaction transaction = DB.beginTransaction()) {
|
||||
*
|
||||
* // this uses L2 bean cache as the transaction
|
||||
* // ... is considered "query only" at this point
|
||||
@@ -2337,7 +2336,7 @@ public class ServerConfig {
|
||||
*
|
||||
* // transaction no longer "query only" once
|
||||
* // ... a bean has been saved etc
|
||||
* Ebean.save(someBean);
|
||||
* DB.save(someBean);
|
||||
*
|
||||
* // will NOT use L2 bean cache as the transaction
|
||||
* // ... is no longer considered "query only"
|
||||
@@ -2356,9 +2355,6 @@ public class ServerConfig {
|
||||
* transaction.setSkipCache(true);
|
||||
* Customer.find.byId(99); // skips l2 bean cache
|
||||
*
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
@@ -2426,7 +2422,7 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the ebeanServer should collection query statistics by ObjectGraphNode.
|
||||
* Return true if query statistics should be collected by ObjectGraphNode.
|
||||
*/
|
||||
public boolean isCollectQueryStatsByNode() {
|
||||
return collectQueryStatsByNode;
|
||||
|
||||
@@ -27,6 +27,9 @@ public class DbPlatformTypeMapping {
|
||||
|
||||
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
|
||||
|
||||
private static final DbPlatformType INET_NATIVE = new DbPlatformType("inet", false);
|
||||
private static final DbPlatformType INET_VARCHAR = new DbPlatformType("varchar", 50);
|
||||
|
||||
private static final DbPlatformType UUID_NATIVE = new DbPlatformType("uuid", false);
|
||||
@SuppressWarnings("unused")
|
||||
private static final DbPlatformType UUID_PLACEHOLDER = new DbPlatformType("uuidPlaceholder");
|
||||
@@ -106,6 +109,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONBLOB, new DbPlatformType("jsonblob"));
|
||||
put(DbType.JSONVARCHAR, new DbPlatformType("jsonvarchar", 1000));
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_NATIVE);
|
||||
|
||||
} else {
|
||||
put(DbType.VARCHAR, new DbPlatformType("varchar", 255));
|
||||
@@ -121,6 +125,7 @@ public class DbPlatformTypeMapping {
|
||||
put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER);
|
||||
// default to native UUID and override on platform configure()
|
||||
put(DbType.UUID, UUID_NATIVE);
|
||||
put(DbType.INET, INET_VARCHAR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ public enum DbType {
|
||||
ARRAY(Types.ARRAY),
|
||||
|
||||
UUID(ExtraDbTypes.UUID),
|
||||
INET(ExtraDbTypes.INET),
|
||||
CDIR(ExtraDbTypes.CDIR),
|
||||
|
||||
POINT(ExtraDbTypes.POINT),
|
||||
POLYGON(ExtraDbTypes.POLYGON),
|
||||
|
||||
@@ -40,6 +40,9 @@ public interface ExtraDbTypes {
|
||||
*/
|
||||
int JSONBlob = 5005;
|
||||
|
||||
int INET = 5020;
|
||||
int CDIR = 5021;
|
||||
|
||||
/**
|
||||
* Geo Point
|
||||
*/
|
||||
|
||||
@@ -60,6 +60,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
DbPlatformType dbBytea = new DbPlatformType("bytea", false);
|
||||
|
||||
dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false));
|
||||
dbTypeMap.put(DbType.INET, new DbPlatformType("inet", false));
|
||||
dbTypeMap.put(DbType.HSTORE, new DbPlatformType("hstore", false));
|
||||
dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
|
||||
dbTypeMap.put(DbType.JSONB, new DbPlatformType("jsonb", false));
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Configuration settings for EbeanServer construction</TITLE>
|
||||
<TITLE>Configuration settings for Database construction</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Configuration settings for EbeanServer construction
|
||||
Configuration settings for Database construction
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
|
||||
@@ -9,7 +9,7 @@ package io.ebean.event;
|
||||
* <p>
|
||||
* Note that getTransaction() on the PersistRequest returns the transaction used
|
||||
* for the insert, update, delete or fetch. To explicitly use this same
|
||||
* transaction you should use this transaction via methods on EbeanServer.
|
||||
* transaction you should use this transaction via methods on Database.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.event;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Database;
|
||||
|
||||
/**
|
||||
* Fired after a bean is constructed, but not yet loaded from database.
|
||||
@@ -9,7 +9,7 @@ import io.ebean.EbeanServer;
|
||||
* properties will get unload. Use {@link BeanPostLoad} instead.
|
||||
* <p>
|
||||
* it's intended to do some dependency-injection here.
|
||||
* If you plan to use this feature you should use {@link EbeanServer#createEntityBean(Class)}
|
||||
* If you plan to use this feature you should use {@link Database#createEntityBean(Class)}
|
||||
* to create new beans.
|
||||
* </p>
|
||||
*/
|
||||
@@ -32,7 +32,7 @@ public interface BeanPostConstructListener {
|
||||
void postConstruct(Object bean);
|
||||
|
||||
/**
|
||||
* Called after {@link EbeanServer#createEntityBean(Class)}. Only for new beans.
|
||||
* Called after {@link Database#createEntityBean(Class)}. Only for new beans.
|
||||
* intended to set default values here.
|
||||
*/
|
||||
void postCreate(Object bean);
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.ebean.meta;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides access to the meta data in EbeanServer such as query execution statistics.
|
||||
* Provides access to the meta data in Database such as query execution statistics.
|
||||
*/
|
||||
public interface MetaInfoManager {
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* Meta data that can be retrieved for the EbeanServer.
|
||||
* Meta data that can be retrieved for a Database instance.
|
||||
*/
|
||||
package io.ebean.meta;
|
||||
|
||||
@@ -3,130 +3,24 @@
|
||||
<title>Ebean API</title>
|
||||
</head>
|
||||
<body BGCOLOR="#ffffff">
|
||||
Ebean Object Relational Mapping (start at
|
||||
<a href='com/avaje/ebean/EbeanServer.html'>EbeanServer</a> or <a href='com/avaje/ebean/Ebean.html'>Ebean</a>).
|
||||
Ebean Object Relational Mapping -
|
||||
<a href='io/ebean/Database.html'>Database</a> or <a href='io/ebean/DB.html'>DB</a>).
|
||||
|
||||
|
||||
<h3>Ebean</h3>
|
||||
<h4><a href='io/ebean/Database.html'>Database</a></h4>
|
||||
<p>
|
||||
Provides the main API for fetching and persisting beans with Ebean.
|
||||
Database provides the main API for fetching and persisting beans.
|
||||
</p>
|
||||
|
||||
<h4><a href='io/ebean/DB.html'>DB</a></h4>
|
||||
<p>
|
||||
For a full description of the query language refer to <a href="com/avaje/ebean/Query.html">Query</a>.
|
||||
DB holds a registry of Database instances by name.
|
||||
</p>
|
||||
|
||||
<h4><a href='https://ebean.io/docs/query'>Query</a></h4>
|
||||
<p>
|
||||
|
||||
Review the documentation for the query capabilities.
|
||||
</p>
|
||||
<div id="overviewexamples">
|
||||
<h3>
|
||||
EXAMPLE 1: Simple fetch
|
||||
</h3>
|
||||
<pre>{@code
|
||||
// fetch order 10
|
||||
Order order = Ebean.find(Order.class, 10);
|
||||
}</pre>
|
||||
|
||||
<h3>
|
||||
EXAMPLE 2: Fetch an Object with associations
|
||||
</h3>
|
||||
<pre>{@code
|
||||
// fetch Customer 7 including their billing and shipping addresses
|
||||
Customer customer = Ebean.find(Customer.class)
|
||||
.fetch("billingAddress");
|
||||
.fetch("shippingAddress");
|
||||
.setId(7)
|
||||
.findOne();
|
||||
|
||||
|
||||
Address billAddr = customer.getBillingAddress();
|
||||
Address shipAddr = customer.getShippingAddress();
|
||||
}</pre>
|
||||
|
||||
<h3>
|
||||
EXAMPLE 3: Fetch a list of Objects with associations
|
||||
</h3>
|
||||
<pre>{@code
|
||||
// Note: This example shows a "Partial Object".
|
||||
// For the product objects associated with the
|
||||
// order details only the product id and name is
|
||||
// fetched (the product objects are partially populated).
|
||||
|
||||
// fetch orders for customer.id = 2
|
||||
List<Order> orderList = Ebean.find(Order.class);
|
||||
.fetch("customer")
|
||||
.fetch("customer.shippingAddress")
|
||||
.fetch("details")
|
||||
.fetch("details.product","name")
|
||||
.where().eq("customer.id",2)
|
||||
.findList();
|
||||
|
||||
|
||||
// Note: Only the product id and name is fetched for the
|
||||
// product details. This is referred to as a
|
||||
// "Partial Object" (one that is partially populated).
|
||||
|
||||
|
||||
// code that traverses the object graph...
|
||||
|
||||
Order order = orderList.get(0);
|
||||
Customer customer = order.getCustomer();
|
||||
Address shipAddr = customer.getShippingAddress();
|
||||
|
||||
List<OrderDetail> details = order.getDetails();
|
||||
OrderDetail detail = details.get(0);
|
||||
Product product = detail.getProduct();
|
||||
String productName = product.getName();
|
||||
|
||||
}</pre>
|
||||
|
||||
<h3>
|
||||
EXAMPLE 4: Create and save an Order
|
||||
</h3>
|
||||
<pre>{@code
|
||||
// get a Customer reference so we don't hit the database
|
||||
Customer custRef = Ebean.getReference(Customer.class, 7);
|
||||
|
||||
// create a new Order object
|
||||
Order newOrder = new Order();
|
||||
newOrder.setStatus(Order.Status.NEW);
|
||||
newOrder.setCustomer(custRef);
|
||||
|
||||
ArrayList orderLines = new ArrayList();
|
||||
newOrder.setLines(orderLines);
|
||||
...
|
||||
|
||||
// add a line to the order
|
||||
Product prodRef = Ebean.getReference(Product.class, 41);
|
||||
OrderLine line = new OrderLine();
|
||||
line.setProduct(prodRef);
|
||||
line.setQuantity(10);
|
||||
orderLines.add(line);
|
||||
...
|
||||
|
||||
// save the order and its lines in a single transaction
|
||||
// NB: assumes CascadeType.PERSIST is set on the order lines association
|
||||
Ebean.save(newOrder);
|
||||
|
||||
}</pre>
|
||||
|
||||
<h3>
|
||||
EXAMPLE 5: Use another database
|
||||
</h3>
|
||||
<pre>{@code
|
||||
// Get access to the Human Resources EbeanServer/Database
|
||||
EbeanServer hrServer = Ebean.getServer("HR");
|
||||
|
||||
|
||||
// fetch contact 3 from the HR database
|
||||
Contact contact = hrServer.find(Contact.class, 3);
|
||||
|
||||
contact.setStatus(Contact.Status.INACTIVE);
|
||||
...
|
||||
|
||||
// save the contact back to the HR database
|
||||
hrServer.save(contact);
|
||||
}</pre>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
@@ -3,29 +3,38 @@
|
||||
<TITLE>Ebean core API</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Core API (see <a href="EbeanServer.html">EbeanServer</a> and <a href="Ebean.html">Ebean</a>).
|
||||
Core API (see <a href="Database.html">Database</a>, <a href="DB.html">DB</a> and <a href="Query.html">Query</a>).
|
||||
|
||||
<h3>Ebean</h3>
|
||||
<h3>Database</h3>
|
||||
<p>
|
||||
Provides the main API for fetching and persisting beans with eBean.
|
||||
Provides the main API for fetching and persisting beans. We can obtain the "default database"
|
||||
via <code>DB.getDefault()</code> or just use methods on DB.
|
||||
</p>
|
||||
|
||||
<pre>{@code
|
||||
// EXAMPLE 1: Simple fetch
|
||||
//========================
|
||||
|
||||
// fetch order 10
|
||||
Order order = Ebean.find(Order.class, 10);
|
||||
// Example find by id
|
||||
|
||||
Order order = DB.find(Order.class, 10);
|
||||
|
||||
|
||||
// Example save
|
||||
|
||||
// EXAMPLE 2: Fetch an Object with associations
|
||||
//=============================================
|
||||
Customer customer = DB.getReference(Customer.class, 42);
|
||||
|
||||
// fetch Customer 7 including their billing and shipping addresses
|
||||
Customer customer =
|
||||
Ebean.find(Customer.class)
|
||||
.setId(7)
|
||||
Order newOrder = new Order();
|
||||
newOrder.setStatus(Order.Status.NEW);
|
||||
newOrder.setCustomer(customer);
|
||||
...
|
||||
|
||||
DB.save(newOrder);
|
||||
|
||||
|
||||
// Example: Eagerly fetching associations
|
||||
|
||||
// fetch Customer 42 including their billing and shipping addresses
|
||||
Customer customer = DB.find(Customer.class)
|
||||
.setId(42)
|
||||
.fetch("billingAddress")
|
||||
.fetch("shippingAddress")
|
||||
.findOne();
|
||||
@@ -33,53 +42,6 @@ Customer customer =
|
||||
Address billAddr = customer.getBillingAddress();
|
||||
Address shipAddr = customer.getShippingAddress();
|
||||
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 3: Create and save an Order
|
||||
//=====================================
|
||||
|
||||
// get a Customer reference so we don't hit the database
|
||||
Customer custRef = Ebean.getReference(Customer.class, 7);
|
||||
|
||||
// create a new Order object
|
||||
Order newOrder = new Order();
|
||||
newOrder.setStatus(Order.Status.NEW);
|
||||
newOrder.setCustomer(custRef);
|
||||
|
||||
ArrayList orderLines = new ArrayList();
|
||||
newOrder.setLines(orderLines);
|
||||
...
|
||||
|
||||
// add a line to the order
|
||||
Product prodRef = Ebean.getReference(Product.class, 41);
|
||||
OrderLine line = new OrderLine();
|
||||
line.setProduct(prodRef);
|
||||
line.setQuantity(10);
|
||||
orderLines.add(line);
|
||||
...
|
||||
|
||||
// save the order and its lines in a single transaction
|
||||
// NB: assumes CascadeType.PERSIST is set on the order lines association
|
||||
Ebean.save(newOrder);
|
||||
|
||||
|
||||
|
||||
// EXAMPLE 4: Use another database
|
||||
//=================================
|
||||
|
||||
// Get access to the Human Resources EbeanServer/Database
|
||||
EbeanServer hrServer = Ebean.getServer("HR");
|
||||
|
||||
|
||||
// fetch contact 3 from the HR database
|
||||
Contact contact = hrServer.find(Contact.class, 3);
|
||||
|
||||
contact.setStatus(Contact.Status.INACTIVE);
|
||||
...
|
||||
|
||||
// save the contact back to the HR database
|
||||
hrServer.save(contact);
|
||||
}</pre>
|
||||
|
||||
</Body>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.plugin;
|
||||
|
||||
/**
|
||||
* A 'plugin' that wants to be configured on startup so it can use features of the EbeanServer itself.
|
||||
* A 'plugin' that wants to be configured on startup so it can use features of the Database itself.
|
||||
*/
|
||||
public interface Plugin {
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extensions to EbeanServer API made available to plugins.
|
||||
* Extensions to Database API made available to plugins.
|
||||
*/
|
||||
public interface SpiServer extends EbeanServer {
|
||||
|
||||
@@ -43,12 +43,12 @@ public interface SpiServer extends EbeanServer {
|
||||
BeanType<?> getBeanTypeForQueueId(String queueId);
|
||||
|
||||
/**
|
||||
* Return the associated DataSource for this EbeanServer instance.
|
||||
* Return the associated DataSource for this Database instance.
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
/**
|
||||
* Return the associated read only DataSource for this EbeanServer instance (can be null).
|
||||
* Return the associated read only DataSource for this Database instance (can be null).
|
||||
*/
|
||||
DataSource getReadOnlyDataSource();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Provides a API for plugins.
|
||||
* <p>
|
||||
* Plugins can get and read meta data about the entity beans and enhance or utilise the
|
||||
* functionality of the EbeanServer.
|
||||
* functionality of the Database.
|
||||
* </p>
|
||||
*/
|
||||
package io.ebean.plugin;
|
||||
|
||||
@@ -4,7 +4,7 @@ import io.ebean.EbeanServer;
|
||||
import io.ebean.config.ServerConfig;
|
||||
|
||||
/**
|
||||
* Creates the EbeanServer implementations. This is used internally by the EbeanServerFactory and is not currently
|
||||
* Creates the Database implementations. This is used internally by the EbeanServerFactory and is not currently
|
||||
* exposed as public API.
|
||||
*/
|
||||
public interface SpiContainer {
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.Locale;
|
||||
*
|
||||
* FileReader reader = new FileReader(f);
|
||||
*
|
||||
* CsvReader<Customer> csvReader = Ebean.createCsvReader(Customer.class);
|
||||
* CsvReader<Customer> csvReader = DB.createCsvReader(Customer.class);
|
||||
*
|
||||
* csvReader.setPersistBatchSize(20);
|
||||
*
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* <pre>{@code
|
||||
* // find some customers ...
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class)
|
||||
* List<Customer> list = DB.find(Customer.class)
|
||||
* .select("id, name, status, shippingAddress")
|
||||
* .fetch("billingAddress","line1, city")
|
||||
* .fetch("billingAddress.country", "*")
|
||||
@@ -18,7 +18,7 @@
|
||||
* .order().desc("id")
|
||||
* .findList();
|
||||
*
|
||||
* JsonContext json = Ebean.json();
|
||||
* JsonContext json = DB.json();
|
||||
*
|
||||
* // output as a JSON string
|
||||
* String jsonOutput = json.toJson(list);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class DeployCreateProperties {
|
||||
* </p>
|
||||
*/
|
||||
private boolean ignoreFieldByName(String fieldName) {
|
||||
if (fieldName.startsWith("_ebean_")) {
|
||||
if (fieldName.startsWith("_ebean_") || fieldName.equals("_$targetDatabase")) {
|
||||
// ignore Ebean internal fields
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -455,6 +455,16 @@ public class DefaultExpressionFactory implements SpiExpressionFactory {
|
||||
return new InExpression(propertyName, values, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public Expression inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return new InExpression(propertyName, values, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* In - property has a value in the array of values.
|
||||
*/
|
||||
|
||||
@@ -912,6 +912,14 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) {
|
||||
if (notEmpty(values)) {
|
||||
add(expr.in(propertyName, values));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> in(String propertyName, Object... values) {
|
||||
add(expr.in(propertyName, values));
|
||||
@@ -1068,6 +1076,18 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> rawOrEmpty(String raw, Collection<?> values) {
|
||||
if (notEmpty(values)) {
|
||||
add(expr.raw(raw, values));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean notEmpty(Collection<?> values) {
|
||||
return values != null && !values.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> startsWith(String propertyName, String value) {
|
||||
add(expr.startsWith(propertyName, value));
|
||||
|
||||
@@ -17,8 +17,16 @@ import java.util.List;
|
||||
|
||||
class InExpression extends AbstractExpression {
|
||||
|
||||
private static final String SQL_TRUE = "1=1";
|
||||
private static final String SQL_FALSE = "1=0";
|
||||
|
||||
private final boolean not;
|
||||
|
||||
/**
|
||||
* Set to true when adding "1=1" predicate (due to null or empty sourceValues).
|
||||
*/
|
||||
private final boolean empty;
|
||||
|
||||
private final Collection<?> sourceValues;
|
||||
|
||||
private List<Object> bindValues;
|
||||
@@ -26,18 +34,27 @@ class InExpression extends AbstractExpression {
|
||||
private boolean multiValueSupported;
|
||||
|
||||
InExpression(String propertyName, Collection<?> sourceValues, boolean not) {
|
||||
this(propertyName, sourceValues, not, false);
|
||||
}
|
||||
|
||||
InExpression(String propertyName, Collection<?> sourceValues, boolean not, boolean orEmpty) {
|
||||
super(propertyName);
|
||||
this.sourceValues = sourceValues;
|
||||
this.not = not;
|
||||
this.empty = orEmpty && (sourceValues == null || sourceValues.isEmpty());
|
||||
}
|
||||
|
||||
InExpression(String propertyName, Object[] array, boolean not) {
|
||||
super(propertyName);
|
||||
this.sourceValues = Arrays.asList(array);
|
||||
this.not = not;
|
||||
this.empty = false;
|
||||
}
|
||||
|
||||
private List<Object> values() {
|
||||
if (empty || sourceValues == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Object> vals = new ArrayList<>(sourceValues.size());
|
||||
for (Object sourceValue : sourceValues) {
|
||||
assert sourceValue != null : "null is not allowed in in-queries";
|
||||
@@ -48,8 +65,8 @@ class InExpression extends AbstractExpression {
|
||||
|
||||
@Override
|
||||
public boolean naturalKey(NaturalKeyQueryData<?> data) {
|
||||
// can't use naturalKey cache for NOT IN
|
||||
if (not) {
|
||||
// can't use naturalKey cache for NOT IN or when "empty"
|
||||
if (not || empty) {
|
||||
return false;
|
||||
}
|
||||
List<Object> copy = data.matchIn(propName, bindValues);
|
||||
@@ -70,11 +87,16 @@ class InExpression extends AbstractExpression {
|
||||
|
||||
@Override
|
||||
public void writeDocQuery(DocQueryContext context) throws IOException {
|
||||
context.writeIn(propName, values().toArray(), not);
|
||||
if (!empty) {
|
||||
context.writeIn(propName, values().toArray(), not);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBindValues(SpiExpressionRequest request) {
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
for (Object value : bindValues) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("null values in 'in(...)' queries must be handled separately!");
|
||||
@@ -108,10 +130,12 @@ class InExpression extends AbstractExpression {
|
||||
|
||||
@Override
|
||||
public void addSql(SpiExpressionRequest request) {
|
||||
|
||||
if (empty) {
|
||||
request.append(SQL_TRUE);
|
||||
return;
|
||||
}
|
||||
if (bindValues.isEmpty()) {
|
||||
String expr = not ? "1=1" : "1=0";
|
||||
request.append(expr);
|
||||
request.append(not ? SQL_TRUE : SQL_FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -142,10 +166,14 @@ class InExpression extends AbstractExpression {
|
||||
builder.append("In[");
|
||||
}
|
||||
builder.append(propName);
|
||||
builder.append(" ?");
|
||||
if (!multiValueSupported) {
|
||||
// query plan specific to the number of parameters in the IN clause
|
||||
builder.append(bindValues.size());
|
||||
if (empty) {
|
||||
builder.append("empty");
|
||||
} else {
|
||||
builder.append(" ?");
|
||||
if (!multiValueSupported) {
|
||||
// query plan specific to the number of parameters in the IN clause
|
||||
builder.append(bindValues.size());
|
||||
}
|
||||
}
|
||||
builder.append("]");
|
||||
}
|
||||
|
||||
@@ -672,6 +672,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.in(propertyName, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> inOrEmpty(String propertyName, Collection<?> values) {
|
||||
return exprList.inOrEmpty(propertyName, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> in(String propertyName, Object... values) {
|
||||
return exprList.in(propertyName, values);
|
||||
@@ -802,6 +807,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.raw(raw, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> rawOrEmpty(String raw, Collection<?> values) {
|
||||
return exprList.rawOrEmpty(raw, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> raw(String raw) {
|
||||
return exprList.raw(raw);
|
||||
|
||||
@@ -69,6 +69,7 @@ public final class BatchControl {
|
||||
* Size of the largest buffer.
|
||||
*/
|
||||
private int bufferMax;
|
||||
private int topCounter;
|
||||
|
||||
private Queue earlyQueue;
|
||||
private Queue lateQueue;
|
||||
@@ -246,6 +247,7 @@ public final class BatchControl {
|
||||
pstmtHolder.clear();
|
||||
beanHoldMap.clear();
|
||||
maxDepth = 0;
|
||||
topCounter = 0;
|
||||
}
|
||||
|
||||
private void flushBuffer(boolean resetTop) throws BatchedSqlException {
|
||||
@@ -319,10 +321,8 @@ public final class BatchControl {
|
||||
if (maybe != -1) {
|
||||
beanDepth = maybe;
|
||||
} else {
|
||||
// we can't be certain of the relative ordering for this type so
|
||||
// flush and reset the batch as we are changing the type of our top level
|
||||
// bean so just keep it simple and flush and reset the top
|
||||
flushReset();
|
||||
// additional "top level" bean type ordered by save() order
|
||||
beanDepth += ++topCounter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.PostgresHelper;
|
||||
import io.ebeaninternal.server.type.RsetDataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
@@ -374,6 +375,11 @@ public class Binder {
|
||||
b.setObject(data);
|
||||
break;
|
||||
|
||||
case DbPlatformType.INET:
|
||||
// data is always a String at this point
|
||||
b.setObject(PostgresHelper.asInet(data.toString()));
|
||||
break;
|
||||
|
||||
case java.sql.Types.OTHER:
|
||||
b.setObject(data, dataType);
|
||||
break;
|
||||
|
||||
@@ -82,8 +82,8 @@ abstract class AbstractMultiValueBind extends MultiValueBind {
|
||||
//case NCLOB:
|
||||
case NCHAR:
|
||||
case NVARCHAR:
|
||||
return "varchar";
|
||||
case ExtraDbTypes.UUID: // Db Native UUID
|
||||
case ExtraDbTypes.UUID: // Postgres cast to uuid[]
|
||||
case ExtraDbTypes.INET: // Postgres cast to inet[]
|
||||
return "varchar";
|
||||
|
||||
default:
|
||||
|
||||
@@ -14,6 +14,9 @@ public class PostgresMultiValueBind extends AbstractMultiValueBind {
|
||||
if (dbType == ExtraDbTypes.UUID) {
|
||||
return (not) ? " != all(?::uuid[])" : " = any(?::uuid[])";
|
||||
}
|
||||
if (dbType == ExtraDbTypes.INET) {
|
||||
return (not) ? " != all(?::inet[])" : " = any(?::inet[])";
|
||||
}
|
||||
String arrayType = getArrayType(dbType);
|
||||
if (arrayType == null) {
|
||||
return super.getInExpression(not, type, size);
|
||||
|
||||
@@ -334,6 +334,24 @@ public final class ConvertInetAddresses {
|
||||
return ip.getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the host address without the square brackets around IPv6 addresses.
|
||||
*/
|
||||
public static String toHostAddress(InetAddress ip) {
|
||||
return ip.getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the IPv4 or IPv6 address without quare brackets around IPv6 addresses.
|
||||
*/
|
||||
public static InetAddress fromHost(String hostAddr) {
|
||||
if (hostAddr.startsWith("[")) {
|
||||
// IPv6 address
|
||||
hostAddr = hostAddr.substring(1, hostAddr.length() - 1);
|
||||
}
|
||||
return forString(hostAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InetAddress representing the literal IPv4 or IPv6 host
|
||||
* portion of a URL, encoded in the format specified by RFC 3986 section 3.2.2.
|
||||
|
||||
@@ -14,6 +14,8 @@ import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.types.Cdir;
|
||||
import io.ebean.types.Inet;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.api.ExtraTypeFactory;
|
||||
import io.ebeaninternal.dbmigration.DbOffline;
|
||||
@@ -37,6 +39,8 @@ import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
@@ -128,7 +132,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
private final ScalarType<?> dateType = new ScalarTypeDate();
|
||||
|
||||
private final ScalarType<?> inetAddressType = new ScalarTypeInetAddress();
|
||||
private final ScalarType<?> urlType = new ScalarTypeURL();
|
||||
private final ScalarType<?> uriType = new ScalarTypeURI();
|
||||
private final ScalarType<?> localeType = new ScalarTypeLocale();
|
||||
@@ -660,11 +663,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
DbEnumValue dbValue = AnnotationUtil.findAnnotation(method, DbEnumValue.class);
|
||||
if (dbValue != null) {
|
||||
boolean integerValues = DbEnumType.INTEGER == dbValue.storage();
|
||||
return createEnumScalarTypeDbValue(enumType, method, integerValues);
|
||||
return createEnumScalarTypeDbValue(enumType, method, integerValues, dbValue.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// look for EnumValue annotations instead
|
||||
return createEnumScalarType2(enumType);
|
||||
}
|
||||
@@ -675,7 +677,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* Return null if the EnumValue annotations are not present/used.
|
||||
* </p>
|
||||
*/
|
||||
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType) {
|
||||
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType, int length) {
|
||||
|
||||
Map<String, String> nameValueMap = new LinkedHashMap<>();
|
||||
|
||||
@@ -693,7 +695,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, 0);
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -975,8 +977,21 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
addType(UUID.class, uuidType);
|
||||
}
|
||||
|
||||
if (offlineMigrationGeneration || (postgres && !config.getPlatformConfig().isDatabaseInetAddressVarchar())) {
|
||||
addInetAddressType(new ScalarTypeInetAddressPostgres());
|
||||
} else {
|
||||
addInetAddressType(new ScalarTypeInetAddress());
|
||||
}
|
||||
|
||||
if (offlineMigrationGeneration || postgres) {
|
||||
addType(Cdir.class, new ScalarTypeCdir.Postgres());
|
||||
addType(Inet.class, new ScalarTypeInet.Postgres());
|
||||
} else {
|
||||
addType(Cdir.class, new ScalarTypeCdir.Varchar());
|
||||
addType(Inet.class, new ScalarTypeInet.Varchar());
|
||||
}
|
||||
|
||||
addType(File.class, fileType);
|
||||
addType(InetAddress.class, inetAddressType);
|
||||
addType(Locale.class, localeType);
|
||||
addType(Currency.class, currencyType);
|
||||
addType(TimeZone.class, timeZoneType);
|
||||
@@ -1063,4 +1078,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
nativeMap.put(Types.TIMESTAMP, timestampType);
|
||||
}
|
||||
|
||||
private void addInetAddressType(ScalarType scalarType) {
|
||||
addType(InetAddress.class, scalarType);
|
||||
addType(Inet4Address.class, scalarType);
|
||||
addType(Inet6Address.class, scalarType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@ public class PostgresHelper {
|
||||
*/
|
||||
public static final String JSONB_TYPE = "jsonb";
|
||||
|
||||
public static final String INET_TYPE = "inet";
|
||||
|
||||
public static Object asInet(String value) throws SQLException {
|
||||
return asObject(INET_TYPE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct and return Postgres specific PG object.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.sql.SQLException;
|
||||
|
||||
abstract class ScalarTypeArrayBase<T> extends ScalarTypeJsonCollection<T> {
|
||||
|
||||
ScalarTypeArrayBase(Class<T> type, int dbType, DocPropertyType docPropertyType) {
|
||||
super(type, dbType, docPropertyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(DataReader reader) throws SQLException {
|
||||
Array array = reader.getArray();
|
||||
if (array == null) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return fromArray((Object[]) array.getArray());
|
||||
} finally {
|
||||
array.free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T fromArray(Object[] array1);
|
||||
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Array;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
@@ -22,7 +21,7 @@ import java.util.UUID;
|
||||
* Type mapped for DB ARRAY type (Postgres only effectively).
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implements ScalarTypeArray {
|
||||
public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements ScalarTypeArray {
|
||||
|
||||
private static ScalarTypeArrayList UUID = new ScalarTypeArrayList("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static ScalarTypeArrayList LONG = new ScalarTypeArrayList("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
@@ -101,7 +100,8 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implemen
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List fromArray(Object[] array1) {
|
||||
@Override
|
||||
protected List fromArray(Object[] array1) {
|
||||
List list = new ArrayList(array1.length);
|
||||
for (Object element : array1) {
|
||||
list.add(converter.toElement(element));
|
||||
@@ -113,16 +113,6 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection<List> implemen
|
||||
return converter.toDbArray(value.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List read(DataReader reader) throws SQLException {
|
||||
Array array = reader.getArray();
|
||||
if (array == null) {
|
||||
return null;
|
||||
} else {
|
||||
return fromArray((Object[]) array.getArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind bind, List value) throws SQLException {
|
||||
if (value == null) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Array;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -21,7 +20,7 @@ import java.util.UUID;
|
||||
/**
|
||||
* Type mapped for DB ARRAY type (Postgres only effectively).
|
||||
*/
|
||||
public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> implements ScalarTypeArray {
|
||||
public class ScalarTypeArraySet<T> extends ScalarTypeArrayBase<Set<T>> implements ScalarTypeArray {
|
||||
|
||||
private static final ScalarTypeArraySet<UUID> UUID = new ScalarTypeArraySet<>("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static final ScalarTypeArraySet<Long> LONG = new ScalarTypeArraySet<>("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
@@ -100,7 +99,8 @@ public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> impl
|
||||
return arrayType + "[]";
|
||||
}
|
||||
|
||||
private Set<T> fromArray(Object[] array1) {
|
||||
@Override
|
||||
protected Set<T> fromArray(Object[] array1) {
|
||||
Set<T> set = new LinkedHashSet<>();
|
||||
for (Object element : array1) {
|
||||
set.add(converter.toElement(element));
|
||||
@@ -112,16 +112,6 @@ public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> impl
|
||||
return converter.toDbArray(value.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<T> read(DataReader reader) throws SQLException {
|
||||
Array array = reader.getArray();
|
||||
if (array == null) {
|
||||
return null;
|
||||
} else {
|
||||
return fromArray((Object[]) array.getArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind bind, Set<T> value) throws SQLException {
|
||||
if (value == null) {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.config.dbplatform.ExtraDbTypes;
|
||||
import io.ebean.types.Cdir;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for Cdir to Varchar or Postgres CDIR.
|
||||
*/
|
||||
public abstract class ScalarTypeCdir extends ScalarTypeBaseVarchar<Cdir> {
|
||||
|
||||
ScalarTypeCdir() {
|
||||
super(Cdir.class, false, ExtraDbTypes.INET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void bind(DataBind b, Cdir value) throws SQLException;
|
||||
|
||||
@Override
|
||||
public Cdir convertFromDbString(String dbValue) {
|
||||
return parse(dbValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToDbString(Cdir beanValue) {
|
||||
return formatValue(beanValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(Cdir value) {
|
||||
return value.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cdir parse(String value) {
|
||||
return new Cdir(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cdir to Varchar.
|
||||
*/
|
||||
public static class Varchar extends ScalarTypeCdir {
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Cdir value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
b.setString(convertToDbString(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cdir to Postgres CDIR.
|
||||
*/
|
||||
public static class Postgres extends ScalarTypeCdir {
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Cdir value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.OTHER);
|
||||
} else {
|
||||
String strValue = convertToDbString(value);
|
||||
b.setObject(PostgresHelper.asInet(strValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.config.dbplatform.ExtraDbTypes;
|
||||
import io.ebean.types.Inet;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for Inet to Varchar or Postgres INET.
|
||||
*/
|
||||
public abstract class ScalarTypeInet extends ScalarTypeBaseVarchar<Inet> {
|
||||
|
||||
ScalarTypeInet(int jdbcType) {
|
||||
super(Inet.class, false, jdbcType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void bind(DataBind b, Inet value) throws SQLException;
|
||||
|
||||
@Override
|
||||
public Inet convertFromDbString(String dbValue) {
|
||||
return parse(dbValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToDbString(Inet beanValue) {
|
||||
return formatValue(beanValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(Inet value) {
|
||||
return value.getAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inet parse(String value) {
|
||||
return new Inet(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inet to Varchar.
|
||||
*/
|
||||
public static class Varchar extends ScalarTypeInet {
|
||||
|
||||
Varchar() {
|
||||
super(Types.VARCHAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Inet value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.VARCHAR);
|
||||
} else {
|
||||
b.setString(convertToDbString(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inet to Postgres INET.
|
||||
*/
|
||||
public static class Postgres extends ScalarTypeInet {
|
||||
|
||||
Postgres() {
|
||||
super(ExtraDbTypes.INET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, Inet value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.OTHER);
|
||||
} else {
|
||||
String strValue = convertToDbString(value);
|
||||
b.setObject(PostgresHelper.asInet(strValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import io.ebean.config.dbplatform.ExtraDbTypes;
|
||||
import io.ebean.text.TextException;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for InetAddress to Postgres INET.
|
||||
*/
|
||||
public class ScalarTypeInetAddressPostgres extends ScalarTypeBaseVarchar<InetAddress> {
|
||||
|
||||
public ScalarTypeInetAddressPostgres() {
|
||||
super(InetAddress.class, false, ExtraDbTypes.INET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, InetAddress value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(Types.OTHER);
|
||||
} else {
|
||||
String strValue = convertToDbString(value);
|
||||
b.setObject(PostgresHelper.asInet(strValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress convertFromDbString(String dbValue) {
|
||||
try {
|
||||
return parse(dbValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException("Error with InetAddresses [" + dbValue + "] " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToDbString(InetAddress beanValue) {
|
||||
return formatValue(beanValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(InetAddress v) {
|
||||
return ConvertInetAddresses.toHostAddress(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress parse(String value) {
|
||||
try {
|
||||
return ConvertInetAddresses.fromHost(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new TextException("Error with InetAddresses [{}]", value, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate<LocalDate> {
|
||||
|
||||
@Override
|
||||
public LocalDate convertFromDate(Date date) {
|
||||
return new LocalDate(date.getTime());
|
||||
return LocalDate.fromDateFields(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,7 +24,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase {
|
||||
|
||||
@AfterClass
|
||||
public static void reportStats() {
|
||||
BasicMetricVisitor basic = Ebean.getDefaultServer().getMetaInfoManager().visitBasic();
|
||||
BasicMetricVisitor basic = DB.getDefault().getMetaInfoManager().visitBasic();
|
||||
for (MetaQueryMetric metric : basic.getDtoQueryMetrics()) {
|
||||
System.out.println(metric);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,25 @@ import static org.assertj.core.api.StrictAssertions.assertThat;
|
||||
public class InExpressionTest extends BaseExpressionTest {
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() throws Exception {
|
||||
public void queryPlanHash_given_diffEmpty_should_differentPlanHash() {
|
||||
|
||||
List<Integer> emptyValues = values();
|
||||
|
||||
InExpression ex1 = new InExpression("foo", emptyValues, false, true);
|
||||
InExpression ex2 = new InExpression("foo", emptyValues, false);
|
||||
InExpression ex3 = new InExpression("foo", emptyValues, false, true);
|
||||
InExpression ex4 = new InExpression("foo", null, false, true);
|
||||
|
||||
ex1.prepareExpression(multi());
|
||||
ex2.prepareExpression(multi());
|
||||
|
||||
different(ex1, ex2);
|
||||
same(ex1, ex3); // same empty
|
||||
same(ex1, ex4); // same null
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_diffPropertyName_should_differentPlanHash() {
|
||||
|
||||
List<Integer> values = values(42, 92);
|
||||
|
||||
@@ -25,7 +43,7 @@ public class InExpressionTest extends BaseExpressionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_diffBindCount_should_differentPlanHash() throws Exception {
|
||||
public void queryPlanHash_given_diffBindCount_should_differentPlanHash() {
|
||||
|
||||
List<Integer> values1 = values(42, 92);
|
||||
List<Integer> values2 = values(42, 92, 82);
|
||||
@@ -39,7 +57,7 @@ public class InExpressionTest extends BaseExpressionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_diffBindCount_withMultiSupport_samePlanHash() throws Exception {
|
||||
public void queryPlanHash_given_diffBindCount_withMultiSupport_samePlanHash() {
|
||||
|
||||
List<Integer> values1 = values(42, 92);
|
||||
List<Integer> values2 = values(42, 92, 82);
|
||||
@@ -53,7 +71,7 @@ public class InExpressionTest extends BaseExpressionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() throws Exception {
|
||||
public void queryPlanHash_given_diffNotFlag_should_differentPlanHash() {
|
||||
|
||||
List<Integer> values = values(42, 92);
|
||||
|
||||
@@ -67,7 +85,7 @@ public class InExpressionTest extends BaseExpressionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryPlanHash_given_sameNotFlag_should_samePlanHash() throws Exception {
|
||||
public void queryPlanHash_given_sameNotFlag_should_samePlanHash() {
|
||||
|
||||
List<Integer> values = values(42, 92);
|
||||
|
||||
|
||||
@@ -3,22 +3,28 @@ package io.ebeaninternal.server.transaction;
|
||||
import io.ebean.config.ProfilingConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class DefaultProfileHandlerTest {
|
||||
@Test
|
||||
public void createProfileStream() throws Exception {
|
||||
|
||||
DefaultProfileHandler handler = new DefaultProfileHandler(new ProfilingConfig());
|
||||
@Test
|
||||
public void createProfileStream() {
|
||||
|
||||
ProfilingConfig profilingConfig = new ProfilingConfig();
|
||||
profilingConfig.setDirectory("target/profiling");
|
||||
|
||||
DefaultProfileHandler handler = new DefaultProfileHandler(profilingConfig);
|
||||
|
||||
assertNotNull(handler.createProfileStream(12));
|
||||
assertNull(handler.createProfileStream(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createProfileStream_when_specificIncludeIds() throws Exception {
|
||||
public void createProfileStream_when_specificIncludeIds() {
|
||||
|
||||
ProfilingConfig config = new ProfilingConfig();
|
||||
config.setDirectory("target/profiling");
|
||||
config.setIncludeProfileIds(new int[]{100,101});
|
||||
|
||||
DefaultProfileHandler handler = new DefaultProfileHandler(config);
|
||||
|
||||
@@ -1,34 +1,46 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class ConvertInetAddressTest {
|
||||
|
||||
@Test
|
||||
public void forString() {
|
||||
|
||||
InetAddress addr = ConvertInetAddresses.forString("128.1.10.23");
|
||||
Assert.assertNotNull(addr);
|
||||
Assert.assertEquals("128.1.10.23", addr.getHostAddress());
|
||||
assertEquals("128.1.10.23", addr.getHostAddress());
|
||||
|
||||
String ip6addr = "2001:db8:85a3:0:0:8a2e:370:7334";
|
||||
InetAddress addr6 = ConvertInetAddresses.forString(ip6addr);
|
||||
String uriAddr6 = ConvertInetAddresses.toUriString(addr6);
|
||||
Assert.assertEquals("[" + ip6addr + "]", uriAddr6);
|
||||
Assert.assertEquals(ip6addr, addr6.getHostAddress());
|
||||
assertEquals("[" + ip6addr + "]", uriAddr6);
|
||||
assertEquals(ip6addr, addr6.getHostAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ipv6_fromHost_getHostAddress() {
|
||||
InetAddress addr2 = ConvertInetAddresses.fromHost("2001:4f8:3:ba:2e0:81ff:fe22:d1f1");
|
||||
assertEquals("2001:4f8:3:ba:2e0:81ff:fe22:d1f1", addr2.getHostAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ipv6_fromHost_getHostAddress_2() {
|
||||
InetAddress addr2 = ConvertInetAddresses.fromHost("2001:db8:85a3:0:0:8a2e:370:7334");
|
||||
assertEquals("2001:db8:85a3:0:0:8a2e:370:7334", addr2.getHostAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toUriString() {
|
||||
|
||||
InetAddress addr = ConvertInetAddresses.forString("128.1.10.23");
|
||||
Assert.assertEquals("128.1.10.23", addr.getHostAddress());
|
||||
assertEquals("128.1.10.23", addr.getHostAddress());
|
||||
|
||||
String uriAddr = ConvertInetAddresses.toUriString(addr);
|
||||
Assert.assertEquals("128.1.10.23", uriAddr);
|
||||
assertEquals("128.1.10.23", uriAddr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ScalarTypeJodaLocalDateTest {
|
||||
|
||||
ScalarTypeJodaLocalDate type = new ScalarTypeJodaLocalDate();
|
||||
private ScalarTypeJodaLocalDate type = new ScalarTypeJodaLocalDate();
|
||||
|
||||
@Test
|
||||
public void convertToMillis_convertFromMillis() throws Exception {
|
||||
public void convertToMillis_convertFromMillis() {
|
||||
|
||||
LocalDate localDate = new LocalDate();
|
||||
long millis = type.convertToMillis(localDate);
|
||||
@@ -23,18 +23,23 @@ public class ScalarTypeJodaLocalDateTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToDate_convertFromDate() throws Exception {
|
||||
public void convertToDate_convertFromDate() {
|
||||
|
||||
convertDate(new LocalDate());
|
||||
convertDate(new LocalDate(1899, 12, 1));
|
||||
convertDate(new LocalDate(1900, 1, 1));
|
||||
}
|
||||
|
||||
private void convertDate(LocalDate localDate) {
|
||||
|
||||
LocalDate localDate = new LocalDate();
|
||||
Date dateValue = type.convertToDate(localDate);
|
||||
LocalDate localDate1 = type.convertFromDate(dateValue);
|
||||
|
||||
assertThat(localDate).isEqualTo(localDate1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void toJdbcType() throws Exception {
|
||||
public void toJdbcType() {
|
||||
|
||||
LocalDate localDate = new LocalDate();
|
||||
Object jdbcType = type.toJdbcType(localDate);
|
||||
@@ -44,7 +49,7 @@ public class ScalarTypeJodaLocalDateTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toBeanType() throws Exception {
|
||||
public void toBeanType() {
|
||||
|
||||
LocalDate localDate = new LocalDate();
|
||||
Date dateValue = type.convertToDate(localDate);
|
||||
|
||||
@@ -27,7 +27,7 @@ public class TestEnumValueAnnotation extends BaseTestCase {
|
||||
|
||||
DB.save(b);
|
||||
|
||||
SqlRow sqlRow = DB.createSqlQuery("select * from e_basic where id = :id")
|
||||
SqlRow sqlRow = DB.sqlQuery("select * from e_basic where id = :id")
|
||||
.setParameter("id", b.getId())
|
||||
.findOne();
|
||||
|
||||
@@ -54,7 +54,7 @@ public class TestEnumValueAnnotation extends BaseTestCase {
|
||||
|
||||
DB.save(b);
|
||||
|
||||
SqlQuery q = DB.createSqlQuery("select * from e_basic_enum_id where status = :status");
|
||||
SqlQuery q = DB.sqlQuery("select * from e_basic_enum_id where status = :status");
|
||||
q.setParameter("status", b.getStatus());
|
||||
|
||||
SqlRow sqlRow = q.findOne();
|
||||
@@ -80,7 +80,7 @@ public class TestEnumValueAnnotation extends BaseTestCase {
|
||||
|
||||
DB.save(b);
|
||||
|
||||
SqlQuery q = DB.createSqlQuery("select * from e_basic_eni where id = :id");
|
||||
SqlQuery q = DB.sqlQuery("select * from e_basic_eni where id = :id");
|
||||
q.setParameter("id", b.getId());
|
||||
|
||||
Optional<SqlRow> sqlRow = q.findOneOrEmpty();
|
||||
|
||||
@@ -1,61 +1,153 @@
|
||||
package org.tests.basic.type;
|
||||
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.TransactionalTestCase;
|
||||
|
||||
import org.tests.model.basic.EWithInetAddr;
|
||||
import org.junit.Assert;
|
||||
import io.ebean.types.Cdir;
|
||||
import io.ebean.types.Inet;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EWithInetAddr;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
public class TestInetAddressType extends TransactionalTestCase {
|
||||
|
||||
@Test
|
||||
public void testIp4() throws UnknownHostException {
|
||||
|
||||
insertUpdateDeleteFind("120.12.12.56");
|
||||
insertUpdateDeleteFind("120.12.12.56", "120.12.12.56");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIp6() throws UnknownHostException {
|
||||
|
||||
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334");
|
||||
if (isPostgres()) {
|
||||
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334");
|
||||
} else {
|
||||
insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3:0:0:8a2e:370:7334");
|
||||
}
|
||||
}
|
||||
|
||||
private void insertUpdateDeleteFind(String ipAddress) throws UnknownHostException {
|
||||
@Test
|
||||
public void test_inet_queryIn() {
|
||||
|
||||
List<Inet> addrs = Inet.listOf("120.12.12.56", "120.12.12.57");
|
||||
|
||||
DB.find(EWithInetAddr.class)
|
||||
.where()
|
||||
.in("inet2", addrs)
|
||||
.findList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_inetAdress_queryIn() throws UnknownHostException {
|
||||
|
||||
List<InetAddress> addrs = new ArrayList<>();
|
||||
addrs.add(InetAddress.getByName("120.12.12.56"));
|
||||
addrs.add(InetAddress.getByName("120.12.12.57"));
|
||||
|
||||
DB.find(EWithInetAddr.class)
|
||||
.where()
|
||||
.in("inetAddress", addrs)
|
||||
.findList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_inet_queryEq() {
|
||||
|
||||
DB.find(EWithInetAddr.class)
|
||||
.where()
|
||||
.eq("inet2", new Inet("120.12.12.58"))
|
||||
.findList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_inet4address_queryEq() throws UnknownHostException {
|
||||
|
||||
DB.find(EWithInetAddr.class)
|
||||
.where()
|
||||
.eq("inetAddress", InetAddress.getByName("120.12.12.58"))
|
||||
.findList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_inet6address_queryEq() throws UnknownHostException {
|
||||
|
||||
DB.find(EWithInetAddr.class)
|
||||
.where()
|
||||
.eq("inetAddress", InetAddress.getByName("2001:db8:85a3:0:0:8a2e:370:7334"))
|
||||
.findList();
|
||||
}
|
||||
|
||||
private void insertUpdateDeleteFind(String ipAddress, String expected) throws UnknownHostException {
|
||||
|
||||
EWithInetAddr bean1 = new EWithInetAddr();
|
||||
bean1.setName("jim");
|
||||
|
||||
InetAddress address1 = InetAddress.getByName(ipAddress);
|
||||
bean1.setInetAddress(address1);
|
||||
bean1.setInet2(new Inet(ipAddress));
|
||||
bean1.setCdir(new Cdir(ipAddress));
|
||||
|
||||
Ebean.save(bean1);
|
||||
|
||||
EWithInetAddr bean2 = Ebean.find(EWithInetAddr.class, bean1.getId());
|
||||
DB.save(bean1);
|
||||
|
||||
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
|
||||
InetAddress address2 = bean2.getInetAddress();
|
||||
Assert.assertNotNull(address2.getHostAddress());
|
||||
Assert.assertEquals(address1.getHostAddress(), address2.getHostAddress());
|
||||
assertNotNull(address2.getHostAddress());
|
||||
assertThat(address1.getHostAddress()).isEqualTo(address2.getHostAddress());
|
||||
assertThat(bean2.getInet2().getAddress()).isEqualTo(expected);
|
||||
assertThat(bean2.getCdir().getAddress()).isEqualTo(expected);
|
||||
|
||||
bean2.setName("modJim");
|
||||
bean2.setInetAddress(InetAddress.getByName("120.12.20.80"));
|
||||
Ebean.save(bean2);
|
||||
Ebean.delete(bean2);
|
||||
bean1.setInet2(new Inet("120.12.20.80"));
|
||||
bean1.setCdir(new Cdir("120.12.20.80"));
|
||||
DB.save(bean2);
|
||||
DB.delete(bean2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void use_null() throws UnknownHostException {
|
||||
public void testIp6_ranges() {
|
||||
|
||||
insertFindDeleteRange("2001:4f8:3:ba::/64");
|
||||
insertFindDeleteRange("2001:4f8:3:ba:2e0:81ff:fe22:d1f1/64");
|
||||
}
|
||||
|
||||
private void insertFindDeleteRange(String ipAddressRange) {
|
||||
|
||||
EWithInetAddr bean1 = new EWithInetAddr();
|
||||
bean1.setName("withRange");
|
||||
bean1.setInet2(new Inet(ipAddressRange));
|
||||
bean1.setCdir(new Cdir(ipAddressRange));
|
||||
|
||||
DB.save(bean1);
|
||||
|
||||
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
|
||||
assertNotNull(bean2.getInet2());
|
||||
assertThat(bean2.getInet2().getAddress()).isEqualTo(ipAddressRange);
|
||||
assertThat(bean2.getCdir().getAddress()).isEqualTo(ipAddressRange);
|
||||
|
||||
DB.delete(bean2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void use_null() {
|
||||
|
||||
EWithInetAddr bean1 = new EWithInetAddr();
|
||||
bean1.setName("jim");
|
||||
|
||||
Ebean.save(bean1);
|
||||
DB.save(bean1);
|
||||
|
||||
EWithInetAddr bean2 = Ebean.find(EWithInetAddr.class, bean1.getId());
|
||||
InetAddress address2 = bean2.getInetAddress();
|
||||
Assert.assertNull(address2);
|
||||
EWithInetAddr bean2 = DB.find(EWithInetAddr.class, bean1.getId());
|
||||
assertNull(bean2.getInetAddress());
|
||||
assertNull(bean2.getInet2());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,5 +57,11 @@ public class TestSqlRowUUID extends BaseTestCase {
|
||||
.findList();
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
|
||||
List<TUuidEntity> list = Ebean.find(TUuidEntity.class)
|
||||
.where().rawOrEmpty("id = any(?::uuid[])", ids)
|
||||
.findList();
|
||||
|
||||
assertThat(list).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.tests.model.aggregation;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -18,7 +18,7 @@ public class TestAggregationMany extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<DMachine> machines = Ebean.find(DMachine.class)
|
||||
List<DMachine> machines = DB.find(DMachine.class)
|
||||
.setDisableLazyLoading(true)
|
||||
.fetchQuery("auxUseAggs", "name, useSecs, fuel")
|
||||
.where().eq("organisation", org)
|
||||
@@ -48,7 +48,7 @@ public class TestAggregationMany extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<DMachine> machines = Ebean.find(DMachine.class)
|
||||
List<DMachine> machines = DB.find(DMachine.class)
|
||||
.setDisableLazyLoading(true)
|
||||
.select("name")
|
||||
.fetch("auxUseAggs", "name, useSecs, fuel")
|
||||
@@ -73,7 +73,7 @@ public class TestAggregationMany extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
List<DMachine> machines = Ebean.find(DMachine.class)
|
||||
List<DMachine> machines = DB.find(DMachine.class)
|
||||
.setDisableLazyLoading(true)
|
||||
.select("name")
|
||||
.fetch("auxUseAggs", "useSecs, fuel")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.tests.model.aggregation;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.BeforeClass;
|
||||
@@ -24,7 +24,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void query_noSelect() {
|
||||
|
||||
Query<DMachineStatsAgg> query = Ebean.find(DMachineStatsAgg.class)
|
||||
Query<DMachineStatsAgg> query = DB.find(DMachineStatsAgg.class)
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.query();
|
||||
|
||||
@@ -36,7 +36,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void query_machineTotalKms_withHaving() {
|
||||
|
||||
Query<DMachineStatsAgg> query = Ebean.find(DMachineStatsAgg.class)
|
||||
Query<DMachineStatsAgg> query = DB.find(DMachineStatsAgg.class)
|
||||
.select("machine, date, totalKms, totalCost")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.having().gt("totalCost", 10)
|
||||
@@ -50,7 +50,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void query_machineTotalKms() {
|
||||
|
||||
Query<DMachineStatsAgg> query = Ebean.find(DMachineStatsAgg.class)
|
||||
Query<DMachineStatsAgg> query = DB.find(DMachineStatsAgg.class)
|
||||
.select("machine, totalKms, totalCost")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.query();
|
||||
@@ -63,7 +63,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void query_byDate() {
|
||||
|
||||
Query<DMachineStatsAgg> query = Ebean.find(DMachineStatsAgg.class)
|
||||
Query<DMachineStatsAgg> query = DB.find(DMachineStatsAgg.class)
|
||||
.select("date, totalKms, hours, rate, totalCost, maxKms")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.having().gt("hours", 2)
|
||||
@@ -77,7 +77,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machineDate_dynamicFormula() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("machine, date, sum(totalKms), sum(hours)")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.having().gt("sum(hours)", 2)
|
||||
@@ -91,7 +91,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machine_dynamicFormula() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("machine, sum(totalKms)")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.having().gt("sum(hours)", 2)
|
||||
@@ -105,7 +105,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machine_dynamicFormula_withJoin() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("sum(totalKms), sum(hours)")
|
||||
.fetch("machine", "name")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
@@ -125,7 +125,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machine_dynamicFormula_withJoin2() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("date, sum(totalKms), sum(hours)")
|
||||
.fetch("machine", "name")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
@@ -146,7 +146,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machine_dynamicFormula_withQueryJoin() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("sum(totalKms), sum(hours)")
|
||||
.fetchQuery("machine", "name")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
@@ -168,7 +168,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_machine_dynamicFormula_withQueryJoin2() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("date, sum(totalKms), sum(hours)")
|
||||
.fetchQuery("machine", "name")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
@@ -190,7 +190,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
@Test
|
||||
public void groupBy_MachineAndDate_dynamicFormula() {
|
||||
|
||||
Query<DMachineStats> query = Ebean.find(DMachineStats.class)
|
||||
Query<DMachineStats> query = DB.find(DMachineStats.class)
|
||||
.select("machine, date, max(rate)")
|
||||
.where().gt("date", LocalDate.now().minusDays(10))
|
||||
.query();
|
||||
@@ -205,7 +205,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Query<DMachine> query = Ebean.find(DMachine.class)
|
||||
Query<DMachine> query = DB.find(DMachine.class)
|
||||
.select("name")
|
||||
.fetch("machineStats", "sum(totalKms)")
|
||||
.where().eq("name", "Machine0")
|
||||
@@ -226,7 +226,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Query<DMachine> query = Ebean.find(DMachine.class)
|
||||
Query<DMachine> query = DB.find(DMachine.class)
|
||||
.select("name")
|
||||
.fetch("machineStats", "date, max(rate), sum(totalKms)")
|
||||
.where().eq("name", "Machine0")
|
||||
@@ -258,7 +258,7 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
machines.add(new DMachine(org, "Machine" + i));
|
||||
}
|
||||
|
||||
Ebean.saveAll(machines);
|
||||
DB.saveAll(machines);
|
||||
|
||||
List<DMachineStats> allStats = new ArrayList<>();
|
||||
|
||||
@@ -280,6 +280,6 @@ public class TestAggregationTopLevel extends BaseTestCase {
|
||||
date = date.minusDays(1);
|
||||
}
|
||||
|
||||
Ebean.saveAll(allStats);
|
||||
DB.saveAll(allStats);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.tests.model.basic;
|
||||
|
||||
import io.ebean.types.Cdir;
|
||||
import io.ebean.types.Inet;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
@@ -20,6 +23,10 @@ public class EWithInetAddr {
|
||||
|
||||
InetAddress inetAddress;
|
||||
|
||||
Inet inet2;
|
||||
|
||||
Cdir cdir;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -52,4 +59,19 @@ public class EWithInetAddr {
|
||||
this.inetAddress = inetAddress;
|
||||
}
|
||||
|
||||
public Inet getInet2() {
|
||||
return inet2;
|
||||
}
|
||||
|
||||
public void setInet2(Inet inet2) {
|
||||
this.inet2 = inet2;
|
||||
}
|
||||
|
||||
public Cdir getCdir() {
|
||||
return cdir;
|
||||
}
|
||||
|
||||
public void setCdir(Cdir cdir) {
|
||||
this.cdir = cdir;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Truck extends Vehicle {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@DbEnumValue
|
||||
@DbEnumValue(length = 3)
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.tests.model.joda;
|
||||
import io.ebean.annotation.CreatedTimestamp;
|
||||
import io.ebean.annotation.UpdatedTimestamp;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.Period;
|
||||
|
||||
@@ -26,6 +27,8 @@ public class BasicJodaEntity {
|
||||
|
||||
Period period;
|
||||
|
||||
LocalDate localDate;
|
||||
|
||||
@Version
|
||||
LocalDateTime version;
|
||||
|
||||
@@ -76,4 +79,12 @@ public class BasicJodaEntity {
|
||||
public void setVersion(LocalDateTime version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setLocalDate(LocalDate localDate) {
|
||||
this.localDate = localDate;
|
||||
}
|
||||
|
||||
public LocalDate getLocalDate() {
|
||||
return localDate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.tests.model.joda;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.Period;
|
||||
import org.junit.Test;
|
||||
@@ -19,8 +20,8 @@ public class TestJodaInsertUpdate extends BaseTestCase {
|
||||
|
||||
BasicJodaEntity e0 = new BasicJodaEntity();
|
||||
e0.setName("foo");
|
||||
|
||||
Ebean.save(e0);
|
||||
e0.setLocalDate(new LocalDate(1899, 12, 1));
|
||||
DB.save(e0);
|
||||
|
||||
LocalDateTime created = e0.getCreated();
|
||||
DateTime updated = e0.getUpdated();
|
||||
@@ -32,7 +33,7 @@ public class TestJodaInsertUpdate extends BaseTestCase {
|
||||
Thread.sleep(10);
|
||||
e0.setName("bar");
|
||||
e0.setPeriod(Period.years(12).plusDays(1));
|
||||
Ebean.save(e0);
|
||||
DB.save(e0);
|
||||
|
||||
LocalDateTime created1 = e0.getCreated();
|
||||
DateTime updated1 = e0.getUpdated();
|
||||
@@ -43,8 +44,31 @@ public class TestJodaInsertUpdate extends BaseTestCase {
|
||||
assertNotSame(version, version1);
|
||||
|
||||
|
||||
BasicJodaEntity found = Ebean.find(BasicJodaEntity.class, e0.getId());
|
||||
BasicJodaEntity found = DB.find(BasicJodaEntity.class, e0.getId());
|
||||
|
||||
assertThat(found.getPeriod()).isEqualTo(e0.getPeriod());
|
||||
assertThat(found.getLocalDate()).isEqualTo(e0.getLocalDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_various() {
|
||||
test_at(new LocalDate(1700, 12, 1));
|
||||
test_at(new LocalDate(1899, 12, 1));
|
||||
test_at(new LocalDate(1900, 1, 1));
|
||||
test_at(new LocalDate());
|
||||
test_at(LocalDate.now());
|
||||
}
|
||||
|
||||
private void test_at(LocalDate date) {
|
||||
|
||||
BasicJodaEntity e0 = new BasicJodaEntity();
|
||||
e0.setName("Various local dates");
|
||||
e0.setLocalDate(date);
|
||||
DB.save(e0);
|
||||
|
||||
BasicJodaEntity found = DB.find(BasicJodaEntity.class, e0.getId());
|
||||
assertThat(found.getLocalDate()).isEqualTo(e0.getLocalDate());
|
||||
|
||||
DB.delete(found);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.tests.model.onetoone.album;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Transaction;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
@@ -24,7 +23,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.delete(Cover.class, cover.getId());
|
||||
DB.delete(Cover.class, cover.getId());
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -43,12 +42,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
Cover cover = new Cover("b1");
|
||||
cover.save();
|
||||
|
||||
Ebean.delete(Cover.class, cover.getId());
|
||||
DB.delete(Cover.class, cover.getId());
|
||||
|
||||
Cover findWhenSoft = Ebean.find(Cover.class, cover.getId());
|
||||
Cover findWhenSoft = DB.find(Cover.class, cover.getId());
|
||||
assertNull(findWhenSoft);
|
||||
|
||||
Cover cover1 = Ebean.find(Cover.class)
|
||||
Cover cover1 = DB.find(Cover.class)
|
||||
.setIncludeSoftDeletes()
|
||||
.setId(cover.getId())
|
||||
.findOne();
|
||||
@@ -63,7 +62,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?; -- bind(false");
|
||||
|
||||
Cover findAgain = Ebean.find(Cover.class, cover.getId());
|
||||
Cover findAgain = DB.find(Cover.class, cover.getId());
|
||||
assertNotNull(findAgain);
|
||||
|
||||
cover.deletePermanent();
|
||||
@@ -77,7 +76,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.getDefaultServer().delete(Cover.class, cover.getId(), null);
|
||||
DB.getDefault().delete(Cover.class, cover.getId(), null);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -97,7 +96,7 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.getDefaultServer().deletePermanent(Cover.class, cover.getId(), null);
|
||||
DB.getDefault().deletePermanent(Cover.class, cover.getId(), null);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -107,13 +106,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllById_when_softDelete() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server.deleteAll(Cover.class, ids(beans));
|
||||
DB.deleteAll(Cover.class, ids(beans));
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -127,18 +125,14 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllById_when_softDelete_withTransaction() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Transaction transaction = server.beginTransaction();
|
||||
try {
|
||||
server.deleteAll(Cover.class, ids(beans), transaction);
|
||||
server.commitTransaction();
|
||||
} finally {
|
||||
server.endTransaction();
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
DB.getDefault().deleteAll(Cover.class, ids(beans), transaction);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
@@ -154,11 +148,11 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
public void ebean_deleteAllPermanentById_when_softDelete() {
|
||||
|
||||
List<Cover> beans = beans(2);
|
||||
Ebean.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.deleteAllPermanent(Cover.class, ids(beans));
|
||||
DB.deleteAllPermanent(Cover.class, ids(beans));
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -168,13 +162,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllPermanentById_when_softDelete() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server.deleteAllPermanent(Cover.class, ids(beans));
|
||||
DB.deleteAllPermanent(Cover.class, ids(beans));
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -185,18 +178,14 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllPermanentById_when_softDelete_withTransaction() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Transaction transaction = server.beginTransaction();
|
||||
try {
|
||||
server.deleteAllPermanent(Cover.class, ids(beans), transaction);
|
||||
server.commitTransaction();
|
||||
} finally {
|
||||
server.endTransaction();
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
DB.getDefault().deleteAllPermanent(Cover.class, ids(beans), transaction);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
@@ -208,18 +197,17 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
public void ebean_deleteAll_when_softDelete() {
|
||||
|
||||
List<Cover> beans = beans(2);
|
||||
Ebean.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.deleteAll(beans);
|
||||
DB.deleteAll(beans);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(3);
|
||||
if (isPersistBatchOnCascade()) {
|
||||
assertThat(sql.get(0)).contains("update cover set s3_url=?, deleted=? where id=?");
|
||||
}
|
||||
else {
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
}
|
||||
}
|
||||
@@ -227,18 +215,17 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAll_when_softDelete() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server.deleteAll(beans);
|
||||
DB.deleteAll(beans);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(3);
|
||||
if (isPersistBatchOnCascade()) {
|
||||
assertThat(sql.get(0)).contains("update cover set s3_url=?, deleted=? where id=?");
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
}
|
||||
else {
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
@@ -248,24 +235,20 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAll_when_softDelete_withTransaction() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Transaction transaction = server.beginTransaction();
|
||||
try {
|
||||
server.deleteAll(beans, transaction);
|
||||
server.commitTransaction();
|
||||
} finally {
|
||||
server.endTransaction();
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
DB.getDefault().deleteAll(beans, transaction);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(3);
|
||||
if (isPersistBatchOnCascade()) {
|
||||
assertThat(sql.get(0)).contains("update cover set s3_url=?, deleted=? where id=?");
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
}
|
||||
else {
|
||||
assertThat(sql.get(0)).contains("update cover set deleted=? where id=?");
|
||||
@@ -275,13 +258,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllPermanent_when_softDelete() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
server.deleteAllPermanent(beans);
|
||||
DB.deleteAllPermanent(beans);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(3);
|
||||
@@ -291,18 +273,14 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase {
|
||||
@Test
|
||||
public void deleteAllPermanent_when_softDelete_withTransaction() {
|
||||
|
||||
EbeanServer server = Ebean.getDefaultServer();
|
||||
List<Cover> beans = beans(2);
|
||||
server.saveAll(beans);
|
||||
DB.saveAll(beans);
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Transaction transaction = server.beginTransaction();
|
||||
try {
|
||||
server.deleteAllPermanent(beans, transaction);
|
||||
server.commitTransaction();
|
||||
} finally {
|
||||
server.endTransaction();
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
DB.getDefault().deleteAllPermanent(beans, transaction);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.tests.o2m.jointable;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
private JtMonkey m2 = new JtMonkey("Uim");
|
||||
|
||||
private void initialInsert() {
|
||||
Ebean.saveAll(Arrays.asList(troop, m0, m1, m2));
|
||||
DB.saveAll(Arrays.asList(troop, m0, m1, m2));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -34,7 +34,7 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
troop.getMonkeys().add(m0);
|
||||
troop.getMonkeys().add(m1);
|
||||
|
||||
Ebean.save(troop);
|
||||
DB.save(troop);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.current();
|
||||
if (isPersistBatchOnCascade()) {
|
||||
@@ -48,14 +48,14 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
assertThat(sql.get(1)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)");
|
||||
}
|
||||
|
||||
long intersectionRows = Ebean.createSqlQuery("select count(*) as total from troop_monkey where troop_pid = ?")
|
||||
long intersectionRows = DB.sqlQuery("select count(*) as total from troop_monkey where troop_pid = ?")
|
||||
.setParameter(1, troop.getPid())
|
||||
.findSingleLong();
|
||||
|
||||
assertThat(intersectionRows).isEqualTo(2L);
|
||||
|
||||
LoggedSqlCollector.current();
|
||||
JtTroop fetchTroop = Ebean.find(JtTroop.class)
|
||||
JtTroop fetchTroop = DB.find(JtTroop.class)
|
||||
.fetch("monkeys")
|
||||
.where().idEq(troop.getPid())
|
||||
.findOne();
|
||||
@@ -67,7 +67,7 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
assertThat(trimSql(sql.get(0))).contains("from troop t0 left join troop_monkey t1z_ on t1z_.troop_pid = t0.pid left join monkey t1 on t1.mid = t1z_.monkey_mid where t0.pid = ?");
|
||||
assertThat(trimSql(sql.get(0))).contains("select t0.pid, t0.name, t0.version, t1.mid, t1.name, t1.food_preference, t1.version");
|
||||
|
||||
Ebean.delete(troop);
|
||||
DB.delete(troop);
|
||||
|
||||
sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
@@ -85,23 +85,22 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
// make m2 dirty ... cascades to an update on Uim
|
||||
m2.setFoodPreference("Apple");
|
||||
trainer.getMonkeys().add(m2);
|
||||
trainer.getMonkeys().add(Ebean.getReference(JtMonkey.class, m1.getMid()));
|
||||
trainer.getMonkeys().add(DB.getReference(JtMonkey.class, m1.getMid()));
|
||||
trainer.getMonkeys().add(new JtMonkey("FAlp"));
|
||||
trainer.getMonkeys().add(new JtMonkey("FBet"));
|
||||
trainer.getMonkeys().add(new JtMonkey("FThe"));
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
Ebean.save(trainer);
|
||||
DB.save(trainer);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.current();
|
||||
//Collections.sort(sql);
|
||||
|
||||
if (isPersistBatchOnCascade()) {
|
||||
assertThat(sql).hasSize(13);
|
||||
assertThat(sql.get(0)).contains("insert into trainer ");
|
||||
assertThat(sql.get(1)).contains("insert into monkey ");
|
||||
assertSqlBind(sql, 2, 4);
|
||||
assertThat(sql.get(5)).contains("update monkey set name=?, food_preference=?, version=? where mid=? and version=?");
|
||||
assertThat(sql.get(5)).contains("update monkey set food_preference=?, version=? where mid=? and version=?");
|
||||
assertThat(sql.get(6)).contains("-- bind(");
|
||||
assertThat(sql.get(7)).contains("insert into trainer_monkey ");
|
||||
assertSqlBind(sql, 8, 12);
|
||||
@@ -116,7 +115,7 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
}
|
||||
|
||||
|
||||
int intersectionRows = Ebean.createSqlQuery("select count(*) as total from trainer_monkey where trainer_tid = ?")
|
||||
int intersectionRows = DB.sqlQuery("select count(*) as total from trainer_monkey where trainer_tid = ?")
|
||||
.setParameter(1, trainer.getTid())
|
||||
.findOne()
|
||||
.getInteger("total");
|
||||
@@ -125,7 +124,7 @@ public class TestOneToManyJoinTable extends BaseTestCase {
|
||||
|
||||
|
||||
LoggedSqlCollector.current();
|
||||
Ebean.delete(trainer);
|
||||
DB.delete(trainer);
|
||||
|
||||
sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package org.tests.query;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.CKeyParent;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.basic.Vehicle;
|
||||
import org.tests.model.basic.VehicleDriver;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -27,10 +27,10 @@ public class TestSubQuery extends BaseTestCase {
|
||||
productIds.add(4);
|
||||
productIds.add(5);
|
||||
|
||||
Query<Order> sq = Ebean.createQuery(Order.class).select("id").where()
|
||||
Query<Order> sq = DB.find(Order.class).select("id").where()
|
||||
.in("details.product.id", productIds).query();
|
||||
|
||||
Ebean.find(Order.class).where().in("id", sq).findList();
|
||||
DB.find(Order.class).where().in("id", sq).findList();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -41,19 +41,19 @@ public class TestSubQuery extends BaseTestCase {
|
||||
List<Integer> productIds = new ArrayList<>();
|
||||
productIds.add(3);
|
||||
|
||||
Query<Order> sq = Ebean.createQuery(Order.class).select("id").where()
|
||||
Query<Order> sq = DB.createQuery(Order.class).select("id").where()
|
||||
.isIn("details.product.id", productIds).query();
|
||||
|
||||
Ebean.find(Order.class).where().isIn("id", sq).findList();
|
||||
DB.find(Order.class).where().isIn("id", sq).findList();
|
||||
}
|
||||
|
||||
public void testCompositeKey() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<CKeyParent> sq = Ebean.createQuery(CKeyParent.class).select("id.oneKey")
|
||||
Query<CKeyParent> sq = DB.createQuery(CKeyParent.class).select("id.oneKey")
|
||||
.setAutoTune(false).where().query();
|
||||
|
||||
Query<CKeyParent> pq = Ebean.find(CKeyParent.class).where().in("id.oneKey", sq).query();
|
||||
Query<CKeyParent> pq = DB.find(CKeyParent.class).where().in("id.oneKey", sq).query();
|
||||
|
||||
pq.findList();
|
||||
|
||||
@@ -93,10 +93,10 @@ public class TestSubQuery extends BaseTestCase {
|
||||
public void testInheritance2() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle")
|
||||
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle")
|
||||
.setAutoTune(false).where().query();
|
||||
|
||||
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
|
||||
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
|
||||
|
||||
pq.findList();
|
||||
|
||||
@@ -118,10 +118,10 @@ public class TestSubQuery extends BaseTestCase {
|
||||
public void testInheritance3() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle")
|
||||
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle")
|
||||
.setAutoTune(false).where().eq("vehicle.licenseNumber", "abc").query();
|
||||
|
||||
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
|
||||
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
|
||||
|
||||
pq.findList();
|
||||
|
||||
@@ -139,10 +139,10 @@ public class TestSubQuery extends BaseTestCase {
|
||||
public void testInheritance4() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<VehicleDriver> sq = Ebean.createQuery(VehicleDriver.class).select("vehicle.id")
|
||||
Query<VehicleDriver> sq = DB.createQuery(VehicleDriver.class).select("vehicle.id")
|
||||
.setAutoTune(false).where().query();
|
||||
|
||||
Query<Vehicle> pq = Ebean.find(Vehicle.class).where().in("id", sq).query();
|
||||
Query<Vehicle> pq = DB.find(Vehicle.class).where().in("id", sq).query();
|
||||
|
||||
pq.findList();
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
package org.tests.query;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class TestWhereIn extends BaseTestCase {
|
||||
|
||||
@@ -15,25 +22,123 @@ public class TestWhereIn extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = Ebean.find(Country.class)
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().in("code", "NZ", "AU")
|
||||
.query();
|
||||
|
||||
query.findList();
|
||||
platformAssertIn(sqlOf(query), "");
|
||||
platformAssertIn(sqlOf(query), "where t0.code");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNotInVarchar() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = Ebean.find(Country.class)
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().notIn("code", "NZ", "SA", "US")
|
||||
.query();
|
||||
|
||||
query.findList();
|
||||
platformAssertNotIn(sqlOf(query), "");
|
||||
platformAssertNotIn(sqlOf(query), "where t0.code");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInOrEmpty_expect_noJoinWhenEmpty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = DB.find(Order.class)
|
||||
.select("id")
|
||||
.where().inOrEmpty("customer.billingAddress.id", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id from o_order t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInOrEmpty_expect_joinWhenNotEmpty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = DB.find(Order.class)
|
||||
.select("id")
|
||||
.where().inOrEmpty("customer.billingAddress.id", Arrays.asList(1)).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("select t0.id from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where t1.billing_address_id ");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInOrEmpty_when_null() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().inOrEmpty("code", null).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInOrEmpty_when_empty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().inOrEmpty("code", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.code, t0.name from o_country t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIn_when_empty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().in("code", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIn_when_null() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().in("code", (Collection)null).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotIn_when_empty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().notIn("code", new ArrayList<>()).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotIn_when_null() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Country> query = DB.find(Country.class)
|
||||
.where().notIn("code", (Collection)null).query();
|
||||
|
||||
query.findList();
|
||||
assertThat(sqlOf(query)).contains("where 1=1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.ebean.Expr;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
@@ -13,6 +14,7 @@ import org.tests.model.basic.OrderDetail;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
@@ -65,6 +67,56 @@ public class TestWhereRawClause extends BaseTestCase {
|
||||
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_notEmpty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
List<String> vals = asList("Rob", "Fiona", "Jack");
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", vals)
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).contains(" t0.id in (select c.id from o_customer c where c.name in (?,?,?))");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_null() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", null)
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawOrEmpty_when_empty() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.select("name")
|
||||
.where()
|
||||
.rawOrEmpty("id in (select c.id from o_customer c where c.name in (?1))", Collections.emptySet())
|
||||
.query();
|
||||
|
||||
List<Customer> list = query.findList();
|
||||
assertThat(list).isNotEmpty();
|
||||
assertThat(sqlOf(query)).isEqualTo("select t0.id, t0.name from o_customer t0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRaw_bindExpansion() {
|
||||
|
||||
@@ -94,6 +146,33 @@ public class TestWhereRawClause extends BaseTestCase {
|
||||
assertThat(list).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(Platform.POSTGRES)
|
||||
public void testRawOrEmpty_PostgresArray() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", asList("Rob", "Fiona", "Jack"))
|
||||
.findList();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", asList())
|
||||
.findList();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
.select("name").where().rawOrEmpty("name = any(?)", null)
|
||||
.findList();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql.get(0)).isEqualTo("select t0.id, t0.name from o_customer t0 where t0.name = any(?); --bind(Array[3]={Rob,Fiona,Jack})");
|
||||
assertThat(sql.get(1)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
|
||||
assertThat(sql.get(2)).isEqualTo("select t0.id, t0.name from o_customer t0; --bind()");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRawWithBindParams() {
|
||||
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
package org.tests.transaction;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Transactional;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.m2m.MnyB;
|
||||
import org.tests.model.m2m.MnyTopic;
|
||||
import org.tests.model.m2m.Role;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestBatchModelFlush extends BaseTestCase {
|
||||
|
||||
@@ -30,4 +39,59 @@ public class TestBatchModelFlush extends BaseTestCase {
|
||||
// the rest is flushed on commit
|
||||
new MnyB("TestBatchModelFlush_5").save();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleTopLevel_expect_singleFlush() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
// 2 unrelated "top level" beans being persisted
|
||||
MnyB m0 = new MnyB("BatchMultipleTop_0");
|
||||
MnyB m1 = new MnyB("BatchMultipleTop_1");
|
||||
Role r0 = new Role("Role_0");
|
||||
Role r1 = new Role("Role_1");
|
||||
|
||||
MnyTopic t0 = new MnyTopic("MnyTopic_0");
|
||||
MnyTopic t1 = new MnyTopic("MnyTopic_1");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
m0.save();
|
||||
DB.save(r0);
|
||||
DB.save(t0);
|
||||
DB.save(t1);
|
||||
|
||||
m1.save();
|
||||
DB.save(r1);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
// DEBUG io.ebean.SUM - txn[1001] BatchControl flush [MnyB:100 i:2, Role:101 i:2, MnyTopic:102 i:2]
|
||||
|
||||
assertThat(sql).hasSize(9);
|
||||
|
||||
// first saved to batch - (depth 100)
|
||||
assertThat(sql.get(0)).contains("insert into mny_b");
|
||||
assertThat(sql.get(1)).contains(" -- bind(BatchMultipleTop_0");
|
||||
assertThat(sql.get(2)).contains(" -- bind(BatchMultipleTop_1");
|
||||
// second saved to batch - (depth 101)
|
||||
assertThat(sql.get(3)).contains("insert into mt_role");
|
||||
assertThat(sql.get(4)).contains(" -- bind(");
|
||||
assertThat(sql.get(5)).contains(" -- bind(");
|
||||
// third saved to batch - (depth 102)
|
||||
assertThat(sql.get(6)).contains("insert into mny_topic");
|
||||
assertThat(sql.get(7)).contains(" -- bind(MnyTopic_0");
|
||||
assertThat(sql.get(8)).contains(" -- bind(MnyTopic_1");
|
||||
|
||||
DB.delete(t0);
|
||||
DB.delete(t1);
|
||||
DB.delete(r0);
|
||||
DB.delete(r1);
|
||||
DB.delete(m0);
|
||||
DB.delete(m1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.tests.types;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.plugin.ExpressionPath;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.tests.model.types.SomeNewTypesBean;
|
||||
|
||||
@@ -27,7 +26,9 @@ import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class TestNewTypes extends BaseTestCase {
|
||||
|
||||
@@ -54,59 +55,59 @@ public class TestNewTypes extends BaseTestCase {
|
||||
bean.setDuration(Duration.ofMinutes(5));
|
||||
|
||||
|
||||
Ebean.save(bean);
|
||||
DB.save(bean);
|
||||
|
||||
bean.setYear(Year.now().minusYears(2));
|
||||
bean.setMonth(Month.SEPTEMBER);
|
||||
|
||||
Ebean.save(bean);
|
||||
DB.save(bean);
|
||||
Thread.sleep(DB_CLOCK_DELTA); // wait, to ensure that instant < Instant.now()
|
||||
List<SomeNewTypesBean> list = Ebean.find(SomeNewTypesBean.class).where().lt("instant", Instant.now()).findList();
|
||||
List<SomeNewTypesBean> list = DB.find(SomeNewTypesBean.class).where().lt("instant", Instant.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("localDate", LocalDate.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("localDate", LocalDate.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().lt("localDateTime", LocalDateTime.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().lt("localDateTime", LocalDateTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().lt("offsetDateTime", OffsetDateTime.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().lt("offsetDateTime", OffsetDateTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().lt("zonedDateTime", ZonedDateTime.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().lt("zonedDateTime", ZonedDateTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("localTime", LocalTime.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("localTime", LocalTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("zoneId", ZoneId.systemDefault().getId()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().eq("zoneId", ZoneId.systemDefault().getId()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("zoneOffset", ZonedDateTime.now().getOffset()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().eq("zoneOffset", ZonedDateTime.now().getOffset()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("yearMonth", YearMonth.of(2014, 9)).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("yearMonth", YearMonth.of(2014, 9)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("monthDay", MonthDay.of(9,22)).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("monthDay", MonthDay.of(9,22)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("year", Year.now()).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("year", Year.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("month", Month.SEPTEMBER).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().le("month", Month.SEPTEMBER).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("path", Paths.get(TEMP_PATH)).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().eq("path", Paths.get(TEMP_PATH)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList();
|
||||
list = DB.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId());
|
||||
SomeNewTypesBean fetched = DB.find(SomeNewTypesBean.class, bean.getId());
|
||||
|
||||
assertEquals(bean.getZoneId(), fetched.getZoneId());
|
||||
assertEquals(bean.getZoneOffset(), fetched.getZoneOffset());
|
||||
@@ -124,9 +125,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
assertEquals(bean.getDuration(), fetched.getDuration());
|
||||
|
||||
|
||||
String asJson = Ebean.json().toJson(fetched);
|
||||
String asJson = DB.json().toJson(fetched);
|
||||
|
||||
SomeNewTypesBean toBean = Ebean.json().toBean(SomeNewTypesBean.class, asJson);
|
||||
SomeNewTypesBean toBean = DB.json().toBean(SomeNewTypesBean.class, asJson);
|
||||
|
||||
assertEquals(bean.getZoneId(), toBean.getZoneId());
|
||||
assertEquals(bean.getZoneOffset(), toBean.getZoneOffset());
|
||||
@@ -151,9 +152,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
|
||||
SomeNewTypesBean bean = new SomeNewTypesBean();
|
||||
|
||||
Ebean.save(bean);
|
||||
DB.save(bean);
|
||||
|
||||
SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId());
|
||||
SomeNewTypesBean fetched = DB.find(SomeNewTypesBean.class, bean.getId());
|
||||
|
||||
assertNull(fetched.getZoneId());
|
||||
assertNull(fetched.getZoneOffset());
|
||||
@@ -195,13 +196,14 @@ public class TestNewTypes extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetGetPathNull() throws Exception {
|
||||
public void testSetGetPathNull() {
|
||||
SomeNewTypesBean refBean = new SomeNewTypesBean();
|
||||
testSetGetPath(refBean);
|
||||
}
|
||||
|
||||
private void testSetGetPath(SomeNewTypesBean refBean) {
|
||||
SomeNewTypesBean testBean = new SomeNewTypesBean();
|
||||
BeanType<SomeNewTypesBean> beanType = Ebean.getDefaultServer().getPluginApi().getBeanType(SomeNewTypesBean.class);
|
||||
BeanType<SomeNewTypesBean> beanType = DB.getDefault().getPluginApi().getBeanType(SomeNewTypesBean.class);
|
||||
ExpressionPath localDate = beanType.getExpressionPath("localDate");
|
||||
ExpressionPath localDateTime = beanType.getExpressionPath("localDateTime");
|
||||
ExpressionPath offsetDateTime = beanType.getExpressionPath("offsetDateTime");
|
||||
@@ -267,8 +269,28 @@ public class TestNewTypes extends BaseTestCase {
|
||||
duration.pathSet(testBean, refBean.getDuration());
|
||||
assertThat(duration.pathGet(testBean)).isEqualTo(refBean.getDuration());
|
||||
|
||||
Ebean.save(refBean);
|
||||
Ebean.save(testBean);
|
||||
DB.save(refBean);
|
||||
DB.save(testBean);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_localDate_pre1900() {
|
||||
|
||||
localDateAt(LocalDate.now());
|
||||
localDateAt(LocalDate.of(1899, 12, 31));
|
||||
localDateAt(LocalDate.of(1899, 12, 1));
|
||||
localDateAt(LocalDate.of(1700, 12, 1));
|
||||
localDateAt(LocalDate.of(1900, 1, 1));
|
||||
}
|
||||
|
||||
private void localDateAt(LocalDate localDate) {
|
||||
|
||||
SomeNewTypesBean bean = new SomeNewTypesBean();
|
||||
bean.setLocalDate(localDate);
|
||||
DB.save(bean);
|
||||
|
||||
SomeNewTypesBean found = DB.find(SomeNewTypesBean.class, bean.getId());
|
||||
|
||||
assertThat(found.getLocalDate()).isEqualTo(localDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,19 +79,19 @@
|
||||
<logger name="org.tests" level="INFO"/>
|
||||
<logger name="io.ebean" level="INFO"/>
|
||||
|
||||
<logger name="org.avaje.docker" level="TRACE"/>
|
||||
<logger name="io.ebean.DDL" level="DEBUG"/>
|
||||
<!--<logger name="org.avaje.docker" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.DDL" level="DEBUG"/>-->
|
||||
|
||||
<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.SQL" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.TXN" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.SUM" level="TRACE"/>-->
|
||||
|
||||
<logger name="io.ebean.cache.TABLEMOD" level="TRACE"/>
|
||||
<!--<logger name="io.ebean.cache.TABLEMOD" level="TRACE"/>-->
|
||||
|
||||
<logger name="io.ebean.cache.QUERY" level="TRACE"/>
|
||||
<logger name="io.ebean.cache.BEAN" level="TRACE"/>
|
||||
<logger name="io.ebean.cache.NATKEY" level="TRACE"/>
|
||||
<logger name="io.ebean.cache.COLL" level="TRACE"/>
|
||||
<!--<logger name="io.ebean.cache.QUERY" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.cache.BEAN" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.cache.NATKEY" level="TRACE"/>-->
|
||||
<!--<logger name="io.ebean.cache.COLL" level="TRACE"/>-->
|
||||
|
||||
<!--<logger name="io.ebeaninternal.server.deploy" level="TRACE"/>-->
|
||||
|
||||
|
||||
Reference in New Issue
Block a user