mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
add support for findSingleAttributeSet
This commit is contained in:
@@ -383,6 +383,15 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Executes the query returning a set of values for a single property.
|
||||
*
|
||||
* This can be used to cache sets.
|
||||
*
|
||||
* @return a HashSet of values for the selegted property
|
||||
*/
|
||||
<A> Set<A> findSingleAttributeSet();
|
||||
|
||||
/**
|
||||
* Execute a query returning a single value of a single property/column.
|
||||
* <pre>{@code
|
||||
|
||||
@@ -368,6 +368,11 @@ public interface ExtendedServer {
|
||||
*/
|
||||
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning a hashset of values for a single property.
|
||||
*/
|
||||
<A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute the query returning at most one entity bean or null (if no matching
|
||||
* bean is found).
|
||||
|
||||
@@ -925,6 +925,11 @@ public interface Query<T> extends CancelableQuery {
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList();
|
||||
|
||||
/**
|
||||
* Execute the query returning a hashset of values for a single property.
|
||||
*/
|
||||
<A> Set<A> findSingleAttributeSet();
|
||||
|
||||
/**
|
||||
* Execute a query returning a single value of a single property/column.
|
||||
* <p>
|
||||
|
||||
+1
@@ -143,6 +143,7 @@ public class BaseQueryTuner {
|
||||
switch (type) {
|
||||
case COUNT:
|
||||
case ATTRIBUTE:
|
||||
case ATTRIBUTE_SET:
|
||||
case ID_LIST:
|
||||
case UPDATE:
|
||||
case DELETE:
|
||||
|
||||
@@ -92,6 +92,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
|
||||
*/
|
||||
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false),
|
||||
|
||||
/**
|
||||
* Find single attribute set.
|
||||
*/
|
||||
ATTRIBUTE_SET(FIND_ATTRIBUTE_SET, "findAttributeSet", false, false),
|
||||
|
||||
/**
|
||||
* Find rowCount.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,7 @@ public interface TxnProfileEventCodes {
|
||||
String FIND_ID_LIST = "fi";
|
||||
String FIND_EXISTS = "ex";
|
||||
String FIND_ATTRIBUTE = "fa";
|
||||
String FIND_ATTRIBUTE_SET = "fas";
|
||||
String FIND_COUNT = "fc";
|
||||
String FIND_SUBQUERY = "fs";
|
||||
|
||||
|
||||
@@ -364,7 +364,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
startQueryPlanCapture();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
for (Plugin plugin : serverPlugins) {
|
||||
@@ -1189,7 +1189,23 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findSingleAttributeList();
|
||||
return request.findSingleAttributeCollection(new ArrayList<>());
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction) {
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ATTRIBUTE_SET, query, transaction);
|
||||
Object result = request.getFromQueryCache();
|
||||
if (result != null) {
|
||||
return (Set<A>) result;
|
||||
}
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findSingleAttributeCollection(new LinkedHashSet<>());
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.ebean.bean.BeanCollection;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -29,11 +30,11 @@ public interface OrmQueryEngine {
|
||||
<T> BeanCollection<T> findMany(OrmQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
* Execute the findSingleAttributeCollection query.
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList(OrmQueryRequest<?> request);
|
||||
<A extends Collection<?>> A findSingleAttributeCollection(OrmQueryRequest<?> request, A collection);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Execute the findVersions query.
|
||||
*/
|
||||
<T> List<Version<T>> findVersions(OrmQueryRequest<T> request);
|
||||
|
||||
@@ -431,8 +431,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList() {
|
||||
return queryEngine.findSingleAttributeList(this);
|
||||
public <A extends Collection<?>> A findSingleAttributeCollection(A collection) {
|
||||
return queryEngine.findSingleAttributeCollection(this, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeanservice.docstore.api.DocQueryRequest;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -120,9 +121,9 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
* Execute the findSingleAttributeCollection query.
|
||||
*/
|
||||
<A> List<A> findSingleAttributeList();
|
||||
<A extends Collection<?>> A findSingleAttributeCollection(A collection);
|
||||
|
||||
/**
|
||||
* Execute returning the ResultSet.
|
||||
|
||||
@@ -467,6 +467,11 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.findSingleAttributeList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> Set<A> findSingleAttributeSet() {
|
||||
return query.findSingleAttributeSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return query.exists();
|
||||
|
||||
@@ -464,6 +464,11 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
|
||||
return exprList.findSingleAttributeList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> Set<A> findSingleAttributeSet() {
|
||||
return exprList.findSingleAttributeSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PagedList<T> findPagedList() {
|
||||
return exprList.findPagedList();
|
||||
|
||||
@@ -24,11 +24,7 @@ import org.slf4j.Logger;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Handles the Object Relational fetching.
|
||||
@@ -91,16 +87,16 @@ public final class CQueryEngine {
|
||||
/**
|
||||
* Build and execute the findSingleAttributeList query.
|
||||
*/
|
||||
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
|
||||
public <A extends Collection<?>> A findSingleAttributeList(OrmQueryRequest<?> request, A collection) {
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request);
|
||||
request.setCancelableQuery(rcQuery);
|
||||
return findAttributeList(request, rcQuery);
|
||||
return findAttributeCollection(request, rcQuery, collection);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <A> List<A> findAttributeList(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery) {
|
||||
private <A extends Collection<?>> A findAttributeCollection(OrmQueryRequest<?> request, CQueryFetchSingleAttribute rcQuery, A collection) {
|
||||
try {
|
||||
List<A> list = (List<A>) rcQuery.findList();
|
||||
rcQuery.findCollection(collection);
|
||||
if (request.logSql()) {
|
||||
logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog(), rcQuery.micros());
|
||||
}
|
||||
@@ -109,13 +105,22 @@ public final class CQueryEngine {
|
||||
}
|
||||
if (request.isQueryCachePut()) {
|
||||
request.addDependentTables(rcQuery.getDependentTables());
|
||||
list = Collections.unmodifiableList(list);
|
||||
request.putToQueryCache(list);
|
||||
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
|
||||
list = new ArrayList<>(list);
|
||||
if (collection instanceof List) {
|
||||
collection = (A) Collections.unmodifiableList((List<?>) collection);
|
||||
request.putToQueryCache(collection);
|
||||
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
|
||||
collection = (A) new ArrayList<>(collection);
|
||||
}
|
||||
} else if (collection instanceof Set) {
|
||||
collection = (A) Collections.unmodifiableSet((Set<?>) collection);
|
||||
request.putToQueryCache(collection);
|
||||
if (Boolean.FALSE.equals(request.query().isReadOnly())) {
|
||||
collection = (A) new LinkedHashSet<>(collection);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return list;
|
||||
return collection;
|
||||
} catch (SQLException e) {
|
||||
throw translate(request, rcQuery.getBindLog(), rcQuery.getGeneratedSql(), e);
|
||||
}
|
||||
@@ -144,7 +149,7 @@ public final class CQueryEngine {
|
||||
public <A> List<A> findIds(OrmQueryRequest<?> request) {
|
||||
CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request);
|
||||
request.setCancelableQuery(rcQuery);
|
||||
return findAttributeList(request, rcQuery);
|
||||
return findAttributeCollection(request, rcQuery, new ArrayList<>());
|
||||
}
|
||||
|
||||
private <T> void logGeneratedSql(OrmQueryRequest<T> request, String sql, String bindLog, long micros) {
|
||||
|
||||
+2
-3
@@ -16,6 +16,7 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@@ -76,11 +77,10 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca
|
||||
/**
|
||||
* Execute the query returning the row count.
|
||||
*/
|
||||
List<Object> findList() throws SQLException {
|
||||
void findCollection(Collection result) throws SQLException {
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
prepareExecute();
|
||||
List<Object> result = new ArrayList<>();
|
||||
while (dataReader.next()) {
|
||||
Object value = reader.read(dataReader);
|
||||
if (containsCounts) {
|
||||
@@ -95,7 +95,6 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca
|
||||
queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros);
|
||||
}
|
||||
getTransaction().profileEvent(this);
|
||||
return result;
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -286,6 +286,11 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> Set<A> findSingleAttributeSet() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> A findSingleAttribute() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
|
||||
@@ -17,6 +17,7 @@ import javax.persistence.PersistenceException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Main Finder implementation.
|
||||
@@ -97,9 +98,9 @@ public final class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
|
||||
public <A extends Collection<?>> A findSingleAttributeCollection(OrmQueryRequest<?> request, A collection) {
|
||||
flushJdbcBatchOnQuery(request);
|
||||
return queryEngine.findSingleAttributeList(request);
|
||||
return queryEngine.findSingleAttributeList(request, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1498,6 +1498,10 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
|
||||
return (List<A>) server.findSingleAttributeList(this, transaction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <A> Set<A> findSingleAttributeSet() {
|
||||
return (Set<A>) server.findSingleAttributeSet(this, transaction);
|
||||
}
|
||||
@Override
|
||||
public final <A> A findSingleAttribute() {
|
||||
List<A> list = findSingleAttributeList();
|
||||
|
||||
@@ -695,6 +695,11 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T findOne(Query<T> query, Transaction transaction) {
|
||||
return null;
|
||||
|
||||
+46
-19
@@ -1,21 +1,23 @@
|
||||
package org.tests.cache;
|
||||
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.ExpressionList;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.test.LoggedSql;
|
||||
import io.ebean.xtest.BaseTestCase;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.cache.EColAB;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestQueryCache extends BaseTestCase {
|
||||
@@ -50,7 +52,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSingleAttribute() {
|
||||
public void findSingleAttributeList() {
|
||||
|
||||
DB.find(EColAB.class).delete();
|
||||
new EColAB("03", "SingleAttribute").save();
|
||||
@@ -76,6 +78,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
|
||||
assertThat(colA_Second).isSameAs(colA_first);
|
||||
|
||||
|
||||
List<String> colA_NotDistinct = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
@@ -89,15 +92,39 @@ public class TestQueryCache extends BaseTestCase {
|
||||
// ensure that findCount & findSingleAttribute use different
|
||||
// slots in cache. If not a "Cannot cast List to int" should happen.
|
||||
int count = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
.where()
|
||||
.eq("columnB", "SingleAttribute")
|
||||
.findCount();
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
.where()
|
||||
.eq("columnB", "SingleAttribute")
|
||||
.findCount();
|
||||
assertThat(count).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSingleAttributeSet() {
|
||||
|
||||
DB.find(EColAB.class).delete();
|
||||
new EColAB("03", "SingleAttribute").save();
|
||||
new EColAB("03", "SingleAttribute").save();
|
||||
ExpressionList<EColAB> query = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
.where()
|
||||
.eq("columnB", "SingleAttribute");
|
||||
Set<String> colA_first = query.findSingleAttributeSet();
|
||||
|
||||
Set<String> colA_Second = query.findSingleAttributeSet();
|
||||
|
||||
assertThat(colA_Second).isSameAs(colA_first).hasSize(1);
|
||||
assertThatThrownBy(colA_first::clear).isInstanceOf(UnsupportedOperationException.class);
|
||||
// ensure, that we do not have cache collisions on same query
|
||||
query.findSingleAttributeList();
|
||||
query.findSingleAttribute();
|
||||
query.findCount();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findCount() {
|
||||
|
||||
@@ -279,7 +306,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
assertSame(list, list2B);
|
||||
|
||||
List<Customer> list3 = DB.find(Customer.class).setUseQueryCache(true).setReadOnly(false).where()
|
||||
.ilike("name", "Rob").findList();
|
||||
.ilike("name", "Rob").findList();
|
||||
|
||||
assertNotSame(list, list3);
|
||||
BeanCollection<Customer> bc3 = (BeanCollection<Customer>) list3;
|
||||
@@ -323,10 +350,10 @@ public class TestQueryCache extends BaseTestCase {
|
||||
// and now, ensure that we hit the database
|
||||
LoggedSql.start();
|
||||
colA_second = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
.findIds();
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
.findIds();
|
||||
sql = LoggedSql.stop();
|
||||
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -335,15 +362,15 @@ public class TestQueryCache extends BaseTestCase {
|
||||
@Test
|
||||
public void findCountDifferentQueriesBit() {
|
||||
DB.getDefault().pluginApi().cacheManager().clearAll();
|
||||
differentFindCount(q->q.bitwiseAny("id",1), q->q.bitwiseAny("id",0));
|
||||
differentFindCount(q->q.bitwiseAll("id",1), q->q.bitwiseAll("id",0));
|
||||
differentFindCount(q -> q.bitwiseAny("id", 1), q -> q.bitwiseAny("id", 0));
|
||||
differentFindCount(q -> q.bitwiseAll("id", 1), q -> q.bitwiseAll("id", 0));
|
||||
// differentFindCount(q->q.bitwiseNot("id",1), q->q.bitwiseNot("id",0)); NOT 1 == AND 1 = 0
|
||||
differentFindCount(q->q.bitwiseAnd("id",1, 0), q->q.bitwiseAnd("id",1, 1));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 1, 0), q -> q.bitwiseAnd("id", 1, 1));
|
||||
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 0), q->q.bitwiseAnd("id",4, 0));
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 1), q->q.bitwiseAnd("id",4, 1));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 2, 0), q -> q.bitwiseAnd("id", 4, 0));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 2, 1), q -> q.bitwiseAnd("id", 4, 1));
|
||||
// Will produce hash collision
|
||||
differentFindCount(q->q.bitwiseAnd("id",10, 0), q->q.bitwiseAnd("id",0, 928210));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 10, 0), q -> q.bitwiseAnd("id", 0, 928210));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user