#1607 - ENH: Add query.exists() query ... as a convenience for "does a row exist" check

This commit is contained in:
rob bygrave
2019-01-09 13:59:53 +13:00
parent ab3e6ccbf7
commit 8a34d6050b
10 changed files with 145 additions and 8 deletions
@@ -226,6 +226,32 @@ public interface ExpressionList<T> {
*/
int update(Transaction transaction);
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query iterating over the results.
*
@@ -1,5 +1,8 @@
package io.ebean;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiTransaction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -42,6 +45,32 @@ public interface ExtendedServer {
*/
void setClock(Clock clock);
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
<T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction);
/**
* Return the number of 'top level' or 'root' entities this query should return.
*
+26
View File
@@ -868,6 +868,32 @@ public interface Query<T> {
*/
boolean isCountDistinct();
/**
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
boolean exists();
/**
* Execute the query returning either a single bean or null (if no matching
* bean is found).
@@ -1363,6 +1363,21 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return !ids.isEmpty();
}
@Override
public <T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction) {
ormQuery.setMaxRows(1);
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, ormQuery, transaction);
try {
request.initTransIfRequired();
List<Object> ids = request.findIds();
return !ids.isEmpty();
} finally {
request.endTransIfRequired();
}
}
@Override
public <A, T> List<A> findIds(Query<T> query, Transaction t) {
@@ -1444,10 +1459,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return queryFuture;
}
public <T> FutureRowCount<T> findFutureRowCount(Query<T> q, Transaction t) {
return findFutureCount(q, t);
}
@Override
public <T> FutureIds<T> findFutureIds(Query<T> query, Transaction t) {
@@ -443,6 +443,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.findSingleAttributeList();
}
@Override
public boolean exists() {
return query.exists();
}
@Override
public T findOne() {
return query.findOne();
@@ -99,6 +99,11 @@ public class FilterExpressionList<T> extends DefaultExpressionList<T> {
return rootQuery.findOneOrEmpty();
}
@Override
public boolean exists() {
return rootQuery.exists();
}
@Override
public ExpressionList<T> having() {
throw new PersistenceException(notAllowedMessage);
@@ -375,6 +375,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
return exprList.apply(fetchPath);
}
@Override
public boolean exists() {
return exprList.exists();
}
@Override
public FutureIds<T> findFutureIds() {
return exprList.findFutureIds();
@@ -1398,6 +1398,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return server.findIds(this, null);
}
@Override
public boolean exists() {
return server.exists(this, null);
}
@Override
public int findCount() {
// a copy of this query is made in the server
@@ -632,6 +632,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
return false;
}
@Override
public <T> boolean exists(SpiQuery<?> ormQuery, SpiTransaction transaction) {
return false;
}
@Override
public <T> T find(Class<T> beanType, Object uid) {
return null;
@@ -3,11 +3,10 @@ package org.tests.query;
import io.ebean.BaseTestCase;
import io.ebean.Ebean;
import io.ebean.Query;
import org.junit.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
@@ -15,6 +14,27 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TestQueryExists extends BaseTestCase {
@Test
public void testExistsBoolean_basic() {
ResetBasicData.reset();
Query<Order> query = Ebean.find(Order.class)
.where().gt("id", 1)
.query();
boolean check = query.exists();
assertThat(check).isTrue();
String sql = sqlOf(query);
if (isH2() || isPostgres()) {
assertThat(sql).contains("select t0.id from o_order t0 where t0.id > ? limit 1");
}
assertThat(Ebean.find(Order.class).where().gt("id", 1).exists()).isTrue();
assertThat(Ebean.find(Order.class).where().or().gt("id", 1).isNull("shipDate").exists()).isTrue();
}
@Test
public void testExists_orders_onOneToMany() {
@@ -73,7 +93,7 @@ public class TestQueryExists extends BaseTestCase {
query.findList();
String sql = query.getGeneratedSql();
Assert.assertTrue(sql.indexOf("exists (") > 0);
assertThat(sql).contains("exists (");
}
@Test
@@ -86,6 +106,6 @@ public class TestQueryExists extends BaseTestCase {
query.findList();
String sql = query.getGeneratedSql();
Assert.assertTrue(sql.indexOf("not exists (") > 0);
assertThat(sql).contains("not exists (");
}
}