mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge remote-tracking branch 'ebean/master' into pr/bugfix/connection_closed_on_clob
This commit is contained in:
@@ -6,10 +6,13 @@ import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -30,6 +33,73 @@ public class DtoQuery2Test extends BaseTestCase {
|
||||
assertThat(list).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dto_findIterator_closeWithResources() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
int counter = 0;
|
||||
try (QueryIterator<DCust> iterator = server()
|
||||
.findDto(DCust.class, "select id, name from o_customer where id > ?")
|
||||
.setParameter(0)
|
||||
.findIterate()) {
|
||||
|
||||
if (iterator.hasNext()) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(counter).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dto_findIterator() {
|
||||
ResetBasicData.reset();
|
||||
final int expectedCount = server().find(Customer.class).findCount();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
int counter = 0;
|
||||
try (final QueryIterator<DCust> iterator = server().findDto(DCust.class, "select id, name from o_customer where id > :id")
|
||||
.setParameter("id", 0)
|
||||
.findIterate()) {
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
final DCust cust = iterator.next();
|
||||
counter++;
|
||||
assertThat(cust).isNotNull();
|
||||
assertThat(cust.getName()).isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(counter).isEqualTo(expectedCount);
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertSql(sql.get(0)).contains("select id, name from o_customer where id > ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dto_findStream() {
|
||||
ResetBasicData.reset();
|
||||
final int expectedCount = server().find(Customer.class).findCount();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
try (final Stream<DCust> stream =
|
||||
server()
|
||||
.findDto(DCust.class, "select id, name from o_customer where id > ?")
|
||||
.setParameter(0)
|
||||
.findStream()) {
|
||||
|
||||
final List<String> names = stream
|
||||
.map(DCust::getName)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertThat(names.size()).isEqualTo(expectedCount);
|
||||
}
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertSql(sql.get(0)).contains("select id, name from o_customer where id > ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dto_findEach_constructorMatch() {
|
||||
|
||||
|
||||
@@ -2,18 +2,21 @@ package io.ebean.common;
|
||||
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EBasic;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class BeanMapTest {
|
||||
|
||||
Object object1 = new Object();
|
||||
Object object2 = new Object();
|
||||
Object object3 = new Object();
|
||||
private final EBasic object1 = new EBasic("o1");
|
||||
private final EBasic object2 = new EBasic("o2");
|
||||
private final EBasic object3 = new EBasic("o3");
|
||||
private final EBasic object4 = new EBasic("o4");
|
||||
private final EBasic object5 = new EBasic("o5");
|
||||
|
||||
private Map<String, Object> all() {
|
||||
Map<String, Object> all = new LinkedHashMap<>();
|
||||
@@ -174,9 +177,7 @@ public class BeanMapTest {
|
||||
@Test
|
||||
public void testClear_given_someBeansInAdditions() throws Exception {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
|
||||
@@ -188,4 +189,252 @@ public class BeanMapTest {
|
||||
assertThat(map.getModifyAdditions()).isEmpty();
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void keySet_add_whenModifyListening() {
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
map.keySet().add("3");
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void keySet_add() {
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.keySet().add("3");
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void keySet_addAll_whenModifyListening() {
|
||||
BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
map.keySet().addAll(asList("3", "4"));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void keySet_addAll() {
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.keySet().addAll(asList("3", "4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keySet_remove() {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
final Set<String> keySet = map.keySet();
|
||||
keySet.remove("1");
|
||||
|
||||
assertThat(keySet.contains("1")).isFalse();
|
||||
assertThat(map).doesNotContainKeys("1");
|
||||
assertThat(map.get("1")).isNull();
|
||||
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keySet_clear() {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
final Set<String> keySet = map.keySet();
|
||||
keySet.clear();
|
||||
|
||||
assertThat(map).isEmpty();
|
||||
assertThat(keySet).isEmpty();
|
||||
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1, object2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keySet_iterator_remove() {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
final Set<String> keySet = map.keySet();
|
||||
final Iterator<String> iterator = keySet.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final String key = iterator.next();
|
||||
if (key.equals("2")) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(map).hasSize(2);
|
||||
assertThat(keySet).hasSize(2);
|
||||
assertThat(keySet).containsExactly("1", "3");
|
||||
assertThat(map).containsKeys("1", "3");
|
||||
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keySet_removeAll() {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
map.put("4", object4);
|
||||
map.put("5", object5);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
final Set<String> keySet = map.keySet();
|
||||
final boolean changed = keySet.removeAll(asList("2", "3", "5"));
|
||||
|
||||
assertThat(changed).isTrue();
|
||||
assertThat(map).hasSize(2);
|
||||
assertThat(keySet).hasSize(2);
|
||||
assertThat(keySet).containsExactly("1", "4");
|
||||
assertThat(map).containsKeys("1", "4");
|
||||
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object2, object3, object5);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void keySet_retainAll() {
|
||||
|
||||
BeanMap<String, Object> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
map.put("4", object4);
|
||||
map.put("5", object5);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
|
||||
final Set<String> keySet = map.keySet();
|
||||
final boolean changed = keySet.retainAll(asList("2", "3", "5"));
|
||||
|
||||
assertThat(changed).isTrue();
|
||||
assertThat(map).hasSize(3);
|
||||
assertThat(keySet).hasSize(3);
|
||||
assertThat(keySet).containsExactly("2", "3", "5");
|
||||
assertThat(map).containsKeys("2", "3", "5");
|
||||
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1, object4);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void values_add() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.values().add(object3);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void values_addAll() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.values().addAll(asList(object3, object5));
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void entrySet_add() {
|
||||
newModifyListeningMap()
|
||||
.entrySet()
|
||||
.add(new AbstractMap.SimpleEntry<>("3", object3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_clear() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
entries.clear();
|
||||
|
||||
assertThat(entries).isEmpty();
|
||||
assertThat(map).isEmpty();
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_remove() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
assertThat(map).hasSize(5);
|
||||
|
||||
final boolean existed1 = entries.remove(new AbstractMap.SimpleEntry<>("1", object1));
|
||||
assertThat(existed1).isTrue();
|
||||
|
||||
final boolean existed22 = entries.remove(new AbstractMap.SimpleEntry<>("22", object1));
|
||||
assertThat(existed22).isFalse();
|
||||
|
||||
assertThat(map).hasSize(4);
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_remove_whenNotEqualValue() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
assertThat(map).hasSize(5);
|
||||
|
||||
final boolean modified = entries.remove(new AbstractMap.SimpleEntry<>("1", object2));
|
||||
assertThat(modified).isFalse();
|
||||
|
||||
assertThat(map).hasSize(5);
|
||||
assertThat(map.getModifyRemovals()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_iterator_remove() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
final Iterator<Map.Entry<String, EBasic>> iterator = entries.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Map.Entry<String, EBasic> entry = iterator.next();
|
||||
if (entry.getKey().equals("2") || entry.getKey().equals("5")) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
assertThat(map).hasSize(3);
|
||||
assertThat(entries).hasSize(3);
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object2, object5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_removeAll() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
entries.removeAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4)));
|
||||
assertThat(map).hasSize(3);
|
||||
assertThat(entries).hasSize(3);
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object1, object4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entrySet_retainAll() {
|
||||
final BeanMap<String, EBasic> map = newModifyListeningMap5();
|
||||
final Set<Map.Entry<String, EBasic>> entries = map.entrySet();
|
||||
|
||||
entries.retainAll(asList(new AbstractMap.SimpleEntry<>("1", object1), new AbstractMap.SimpleEntry<>("3", object4), new AbstractMap.SimpleEntry<>("4", object4)));
|
||||
assertThat(map).hasSize(2);
|
||||
assertThat(entries).hasSize(2);
|
||||
assertThat(map.getModifyRemovals()).containsExactly(object2, object3, object5);
|
||||
}
|
||||
|
||||
private BeanMap<String, EBasic> newModifyListeningMap() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
return map;
|
||||
}
|
||||
|
||||
private BeanMap<String, EBasic> newModifyListeningMap5() {
|
||||
BeanMap<String, EBasic> map = new BeanMap<>();
|
||||
map.put("1", object1);
|
||||
map.put("2", object2);
|
||||
map.put("3", object3);
|
||||
map.put("4", object4);
|
||||
map.put("5", object5);
|
||||
map.setModifyListening(BeanCollection.ModifyListenMode.ALL);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ public class ServerConfigTest {
|
||||
props.setProperty("dbOffline", "true");
|
||||
props.setProperty("jsonDateTime", "MILLIS");
|
||||
props.setProperty("jsonDate", "MILLIS");
|
||||
props.setProperty("jsonDirtyByDefault", "false");
|
||||
props.setProperty("autoReadOnlyDataSource", "true");
|
||||
props.setProperty("disableL2Cache", "true");
|
||||
props.setProperty("notifyL2CacheInForeground", "true");
|
||||
@@ -103,6 +104,9 @@ public class ServerConfigTest {
|
||||
assertEquals(PlatformConfig.DbUuid.BINARY, serverConfig.getPlatformConfig().getDbUuid());
|
||||
assertEquals(JsonConfig.DateTime.MILLIS, serverConfig.getJsonDateTime());
|
||||
assertEquals(JsonConfig.Date.MILLIS, serverConfig.getJsonDate());
|
||||
assertFalse(serverConfig.isJsonDirtyByDefault());
|
||||
serverConfig.setJsonDirtyByDefault(true);
|
||||
assertTrue(serverConfig.isJsonDirtyByDefault());
|
||||
|
||||
assertEquals("r0,users,orgs", serverConfig.getEnabledL2Regions());
|
||||
|
||||
@@ -155,6 +159,7 @@ public class ServerConfigTest {
|
||||
assertFalse(serverConfig.isIdGeneratorAutomatic());
|
||||
assertEquals(JsonConfig.DateTime.ISO8601, serverConfig.getJsonDateTime());
|
||||
assertEquals(JsonConfig.Date.ISO8601, serverConfig.getJsonDate());
|
||||
assertTrue(serverConfig.isJsonDirtyByDefault());
|
||||
assertTrue(serverConfig.getPlatformConfig().isCaseSensitiveCollation());
|
||||
assertTrue(serverConfig.isAutoLoadModuleInfo());
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.config.dbplatform;
|
||||
|
||||
import io.ebean.config.PlatformConfig;
|
||||
import io.ebean.config.dbplatform.oracle.Oracle11Platform;
|
||||
import io.ebean.config.dbplatform.oracle.OraclePlatform;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -8,17 +9,27 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class OraclePlatformTest {
|
||||
|
||||
@Test
|
||||
public void columnAliasPrefix_Oracle11Platform() {
|
||||
Oracle11Platform platform11 = new Oracle11Platform();
|
||||
assertThat(platform11.columnAliasPrefix).isEqualTo("c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void columnAliasPrefix_OraclePlatform() {
|
||||
OraclePlatform platform = new OraclePlatform();
|
||||
assertThat(platform.columnAliasPrefix).isEqualTo("c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uuid_default() {
|
||||
|
||||
OraclePlatform platform = new OraclePlatform();
|
||||
platform.configure(new PlatformConfig(), false);
|
||||
DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID);
|
||||
|
||||
assertThat(dbType.renderType(0, 0)).isEqualTo("varchar2(40)");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void uuid_as_binary() {
|
||||
|
||||
|
||||
@@ -453,6 +453,16 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
public <T> void findDtoEachWhile(SpiDtoQuery<T> query, Predicate<T> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> QueryIterator<T> findDtoIterate(SpiDtoQuery<T> query) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> findDtoStream(SpiDtoQuery<T> query) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> findDtoList(SpiDtoQuery<T> query) {
|
||||
return null;
|
||||
@@ -493,6 +503,10 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void findSingleAttributeEach(SpiSqlQuery query, Class<T> cls, Consumer<T> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T findOneMapper(SpiSqlQuery query, RowMapper<T> mapper) {
|
||||
return null;
|
||||
|
||||
+35
-1
@@ -288,7 +288,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_removeJoinToMany_when_filterMany() {
|
||||
public void test_filterMany_included() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetch("details")
|
||||
@@ -301,6 +301,40 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("details", "details.product", "customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterMany_excludedByOrdering() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetch("customer")
|
||||
.fetch("customer.contacts")
|
||||
.fetch("details")
|
||||
.fetch("details.product")
|
||||
.filterMany("details").eq("orderQuantity", 10)
|
||||
.query();
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterMany_excludedExplicitly() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetchQuery("details")
|
||||
.fetch("details.product")
|
||||
.fetch("customer")
|
||||
.fetch("customer.contacts")
|
||||
.filterMany("details").eq("orderQuantity", 10)
|
||||
.query();
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
|
||||
}
|
||||
|
||||
|
||||
+29
-8
@@ -1,25 +1,28 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ScalarTypeLocalDateTimeTest {
|
||||
|
||||
ScalarTypeLocalDateTime type = new ScalarTypeLocalDateTime(JsonConfig.DateTime.MILLIS);
|
||||
private final ScalarTypeLocalDateTime type = new ScalarTypeLocalDateTime(JsonConfig.DateTime.MILLIS);
|
||||
|
||||
private final JsonFactory factory = new JsonFactory();
|
||||
|
||||
// warm up
|
||||
LocalDateTime warmUp = LocalDateTime.now();
|
||||
private final LocalDateTime warmUp = LocalDateTime.now();
|
||||
|
||||
@Test
|
||||
public void testNowToMillis() throws Exception {
|
||||
public void testNowToMillis() {
|
||||
|
||||
warmUp.hashCode();
|
||||
|
||||
@@ -29,7 +32,7 @@ public class ScalarTypeLocalDateTimeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertToMillis() throws Exception {
|
||||
public void testConvertToMillis() {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now().withNano(123_000_000); // jdk11 workaround
|
||||
long asMillis = type.convertToMillis(now);
|
||||
@@ -39,7 +42,7 @@ public class ScalarTypeLocalDateTimeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertFromTimestamp() throws Exception {
|
||||
public void testConvertFromTimestamp() {
|
||||
|
||||
Timestamp now = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
@@ -74,6 +77,24 @@ public class ScalarTypeLocalDateTimeTest {
|
||||
assertEquals(timestamp, timestamp1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testJsonRaw() throws Exception {
|
||||
|
||||
final LocalDateTime of = LocalDateTime.of(2020, 5, 4, 13, 20, 40);
|
||||
|
||||
ScalarTypeLocalDateTime typeIso = new ScalarTypeLocalDateTime(JsonConfig.DateTime.ISO8601);
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
JsonGenerator generator = factory.createGenerator(writer);
|
||||
|
||||
typeIso.jsonWrite(generator, of);
|
||||
generator.flush();
|
||||
|
||||
assertThat(of.toString()).isEqualTo("2020-05-04T13:20:40");
|
||||
assertThat(writer.toString()).isEqualTo("\"2020-05-04T13:20:40\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJson() throws Exception {
|
||||
|
||||
|
||||
+44
-6
@@ -5,6 +5,8 @@ import org.junit.Test;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -14,12 +16,12 @@ import static org.junit.Assert.assertTrue;
|
||||
public class ScalarTypeOffsetDateTimeTest {
|
||||
|
||||
|
||||
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS);
|
||||
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS, ZoneOffset.systemDefault());
|
||||
|
||||
OffsetDateTime warmUp = OffsetDateTime.now();
|
||||
|
||||
@Test
|
||||
public void testConvertToMillis() throws Exception {
|
||||
public void testConvertToMillis() {
|
||||
|
||||
warmUp.hashCode();
|
||||
|
||||
@@ -30,7 +32,43 @@ public class ScalarTypeOffsetDateTimeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertFromTimestamp() throws Exception {
|
||||
public void convertFromInstant_with_UTC_expect_matchingZoneOffset() {
|
||||
final TimeZone timeZoneToUse = TimeZone.getTimeZone("UTC");
|
||||
final ZoneOffset expectedZoneOffset = ZoneOffset.UTC;
|
||||
|
||||
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedZoneOffset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromInstant_with_EST_expect_matchingZoneOffset() {
|
||||
final TimeZone timeZoneToUse = TimeZone.getTimeZone("EST");
|
||||
final ZoneOffset expectedOffset = OffsetDateTime.now(timeZoneToUse.toZoneId()).getOffset();
|
||||
|
||||
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedOffset);
|
||||
}
|
||||
|
||||
private void convertFromInstantWithConfiguredTimeZone(TimeZone timeZoneToUse, ZoneOffset expectedZoneOffset) {
|
||||
TimeZone previous = TimeZone.getDefault();
|
||||
try {
|
||||
OffsetDateTime dateTime = OffsetDateTime.parse("2021-01-01T00:00:00+11:00");
|
||||
|
||||
// test ScalarTypeOffsetDateTime with the configured timeZone to use
|
||||
ScalarTypeOffsetDateTime type = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.MILLIS, timeZoneToUse.toZoneId());
|
||||
|
||||
// effectively we desire to ignore the system timezone and use the configured one
|
||||
TimeZone.setDefault(timeZoneToUse);
|
||||
|
||||
final OffsetDateTime offsetDateTime = type.convertFromInstant(dateTime.toInstant());
|
||||
|
||||
assertEquals(expectedZoneOffset, offsetDateTime.getOffset());
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertFromTimestamp() {
|
||||
|
||||
Timestamp now = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
@@ -69,11 +107,11 @@ public class ScalarTypeOffsetDateTimeTest {
|
||||
JsonTester<OffsetDateTime> jsonTester = new JsonTester<>(type);
|
||||
jsonTester.test(now);
|
||||
|
||||
ScalarTypeOffsetDateTime typeNanos = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.NANOS);
|
||||
ScalarTypeOffsetDateTime typeNanos = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.NANOS, ZoneOffset.systemDefault());
|
||||
jsonTester = new JsonTester<>(typeNanos);
|
||||
jsonTester.test(now);
|
||||
|
||||
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601);
|
||||
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601, ZoneOffset.systemDefault());
|
||||
jsonTester = new JsonTester<>(typeIso);
|
||||
jsonTester.test(now);
|
||||
}
|
||||
@@ -81,7 +119,7 @@ public class ScalarTypeOffsetDateTimeTest {
|
||||
@Test
|
||||
public void isoJsonFormatParse() {
|
||||
|
||||
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601);
|
||||
ScalarTypeOffsetDateTime typeIso = new ScalarTypeOffsetDateTime(JsonConfig.DateTime.ISO8601, ZoneOffset.systemDefault());
|
||||
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
String asJson = typeIso.toJsonISO8601(now);
|
||||
|
||||
+45
-6
@@ -4,7 +4,11 @@ import io.ebean.config.JsonConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.*;
|
||||
@@ -12,12 +16,12 @@ import static org.junit.Assert.*;
|
||||
public class ScalarTypeZonedDateTimeTest {
|
||||
|
||||
|
||||
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS);
|
||||
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS, ZoneId.systemDefault());
|
||||
|
||||
ZonedDateTime warmUp = ZonedDateTime.now();
|
||||
|
||||
@Test
|
||||
public void testConvertToMillis() throws Exception {
|
||||
public void testConvertToMillis() {
|
||||
|
||||
warmUp.hashCode();
|
||||
|
||||
@@ -29,7 +33,7 @@ public class ScalarTypeZonedDateTimeTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertFromTimestamp() throws Exception {
|
||||
public void testConvertFromTimestamp() {
|
||||
|
||||
Timestamp now = new Timestamp(System.currentTimeMillis());
|
||||
|
||||
@@ -39,6 +43,41 @@ public class ScalarTypeZonedDateTimeTest {
|
||||
assertEquals(now, timestamp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromInstant_with_UTC_expect_matchingZoneOffset() {
|
||||
final TimeZone timeZoneToUse = TimeZone.getTimeZone("UTC");
|
||||
final ZoneOffset expectedZoneOffset = ZoneOffset.UTC;
|
||||
|
||||
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedZoneOffset);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertFromInstant_with_EST_expect_matchingZoneOffset() {
|
||||
final TimeZone timeZoneToUse = TimeZone.getTimeZone("EST");
|
||||
final ZoneOffset expectedOffset = OffsetDateTime.now(timeZoneToUse.toZoneId()).getOffset();
|
||||
|
||||
convertFromInstantWithConfiguredTimeZone(timeZoneToUse, expectedOffset);
|
||||
}
|
||||
|
||||
private void convertFromInstantWithConfiguredTimeZone(TimeZone timeZoneToUse, ZoneOffset expectedZoneOffset) {
|
||||
TimeZone previous = TimeZone.getDefault();
|
||||
try {
|
||||
OffsetDateTime dateTime = OffsetDateTime.parse("2021-01-01T00:00:00+11:00");
|
||||
|
||||
// test ScalarTypeOffsetDateTime with the configured timeZone to use
|
||||
ScalarTypeZonedDateTime type = new ScalarTypeZonedDateTime(JsonConfig.DateTime.MILLIS, timeZoneToUse.toZoneId());
|
||||
|
||||
// effectively we desire to ignore the system timezone and use the configured one
|
||||
TimeZone.setDefault(timeZoneToUse);
|
||||
|
||||
final ZonedDateTime zonedDateTime = type.convertFromInstant(dateTime.toInstant());
|
||||
|
||||
assertEquals(expectedZoneOffset, zonedDateTime.getOffset());
|
||||
|
||||
} finally {
|
||||
TimeZone.setDefault(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToJdbcType() throws Exception {
|
||||
@@ -68,11 +107,11 @@ public class ScalarTypeZonedDateTimeTest {
|
||||
JsonTester<ZonedDateTime> jsonTester = new JsonTester<>(type);
|
||||
jsonTester.test(now);
|
||||
|
||||
ScalarTypeZonedDateTime typeNanos = new ScalarTypeZonedDateTime(JsonConfig.DateTime.NANOS);
|
||||
ScalarTypeZonedDateTime typeNanos = new ScalarTypeZonedDateTime(JsonConfig.DateTime.NANOS, ZoneId.systemDefault());
|
||||
jsonTester = new JsonTester<>(typeNanos);
|
||||
jsonTester.test(now);
|
||||
|
||||
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601);
|
||||
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601, ZoneId.systemDefault());
|
||||
jsonTester = new JsonTester<>(typeIso);
|
||||
jsonTester.test(now);
|
||||
}
|
||||
@@ -80,7 +119,7 @@ public class ScalarTypeZonedDateTimeTest {
|
||||
@Test
|
||||
public void toJsonISO8601() {
|
||||
|
||||
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601);
|
||||
ScalarTypeZonedDateTime typeIso = new ScalarTypeZonedDateTime(JsonConfig.DateTime.ISO8601, ZoneId.systemDefault());
|
||||
|
||||
ZonedDateTime now = ZonedDateTime.now();
|
||||
String asJson = typeIso.toJsonISO8601(now);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package org.tests.basic;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.FutureIds;
|
||||
import io.ebean.Query;
|
||||
import io.ebeantest.LoggedSql;
|
||||
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.OrderDetail;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -36,4 +40,36 @@ public class TestFetchId extends BaseTestCase {
|
||||
List<Object> idList = futureIds.get();
|
||||
assertThat(idList).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchIdWithExists() throws InterruptedException, ExecutionException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<OrderDetail> subQuery = Ebean.find(OrderDetail.class)
|
||||
.alias("sq")
|
||||
.where().raw("details.id = sq.id").query();
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.where().exists(subQuery)
|
||||
.orderBy("orderDate").query();
|
||||
|
||||
List<Object> ids = query.findIds();
|
||||
// TODO: assert(query.getGeneratedSql())
|
||||
assertThat(ids).isNotEmpty();
|
||||
FutureIds<Order> futureIds = query.findFutureIds();
|
||||
|
||||
// wait for all the id's to be fetched
|
||||
List<Object> idList = futureIds.get();
|
||||
assertThat(idList).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFetchIdWithOrderFormula() throws InterruptedException, ExecutionException {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = DB.find(Order.class).orderBy("totalItems");
|
||||
query.findIds();
|
||||
// TODO: assert(query.getGeneratedSql())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class TestEncrypt extends BaseTestCase {
|
||||
|
||||
|
||||
@Test
|
||||
@ForPlatform(Platform.H2) // only run this on H2 - PGCrypto not happy on CI server
|
||||
@ForPlatform({Platform.H2, Platform.SQLSERVER}) // only run this on H2 - PGCrypto not happy on CI server
|
||||
public void testQueryBind() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
@@ -36,7 +36,7 @@ public class TestEncrypt extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(Platform.H2) // only run this on H2 - PGCrypto not happy on CI server
|
||||
@ForPlatform({Platform.H2, Platform.SQLSERVER}) // only run this on H2 - PGCrypto not happy on CI server
|
||||
public void testQueryJoin() {
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
@@ -99,7 +99,7 @@ public class TestEncrypt extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(Platform.H2)
|
||||
@ForPlatform({Platform.H2, Platform.SQLSERVER})
|
||||
public void test() {
|
||||
|
||||
DB.find(EBasicEncrypt.class).delete();
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.tests.model.json.EBasicJsonList;
|
||||
import org.tests.model.json.PlainBean;
|
||||
import org.tests.model.json.PlainBeanDirtyAware;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -59,18 +60,20 @@ public class TestDbJson_Jackson3 extends BaseTestCase {
|
||||
EBasicJsonList bean = new EBasicJsonList();
|
||||
bean.setName("p1");
|
||||
bean.setPlainBean(contentBean);
|
||||
bean.setBeanList(Arrays.asList(contentBean));
|
||||
|
||||
DB.save(bean);
|
||||
final EBasicJsonList found = DB.find(EBasicJsonList.class, bean.getId());
|
||||
// json bean not modified but not aware
|
||||
// ideally don't load the json content if we are not going to modify it
|
||||
found.setName("p1-mod");
|
||||
found.setBeanList(null);
|
||||
|
||||
LoggedSql.start();
|
||||
DB.save(found);
|
||||
|
||||
final List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("update ebasic_json_list set name=?, beans=?, bean_list=?, plain_bean=?, version=? where id=?");
|
||||
assertThat(sql.get(0)).contains("update ebasic_json_list set name=?, bean_list=?, plain_bean=?, version=? where id=?");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.tests.lazyloadconf;
|
||||
|
||||
import io.ebean.annotation.Cache;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Cache
|
||||
@Table(name = "app_config")
|
||||
public class AppConfig {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private Integer id;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "appConfig")
|
||||
//@JoinColumn(name = "id", referencedColumnName = "id")
|
||||
private List<AppConfigControl> items;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<AppConfigControl> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<AppConfigControl> items) {
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.tests.lazyloadconf;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "app_config_control")
|
||||
public class AppConfigControl {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "config_id", referencedColumnName = "id")
|
||||
private AppConfig appConfig;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public AppConfig getAppConfig() {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
public void setAppConfig(AppConfig appConfig) {
|
||||
this.appConfig = appConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.tests.lazyloadconf;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class BeanCollectionLazyLoadingTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
AppConfig globalAppConfig = new AppConfig();
|
||||
globalAppConfig.setId(1);
|
||||
globalAppConfig.setItems(new ArrayList<>());
|
||||
AppConfigControl global = new AppConfigControl();
|
||||
global.setId(1);
|
||||
global.setName("global");
|
||||
global.setAppConfig(globalAppConfig);
|
||||
globalAppConfig.getItems().add(global);
|
||||
DB.save(globalAppConfig);
|
||||
|
||||
AppConfig userAppConfig = new AppConfig();
|
||||
userAppConfig.setId(2);
|
||||
userAppConfig.setItems(new ArrayList<>());
|
||||
AppConfigControl user = new AppConfigControl();
|
||||
user.setId(2);
|
||||
user.setName("user");
|
||||
user.setAppConfig(userAppConfig);
|
||||
userAppConfig.getItems().add(user);
|
||||
DB.save(userAppConfig);
|
||||
|
||||
AppConfig otherAppConfig = new AppConfig();
|
||||
otherAppConfig.setId(3);
|
||||
otherAppConfig.setItems(new ArrayList<>());
|
||||
DB.save(otherAppConfig);
|
||||
|
||||
Relationship globalRe = new Relationship();
|
||||
globalRe.setId(1);
|
||||
globalRe.setAppConfig(globalAppConfig);
|
||||
DB.save(globalRe);
|
||||
|
||||
Relationship userRe = new Relationship();
|
||||
userRe.setId(2);
|
||||
userRe.setAppConfig(userAppConfig);
|
||||
DB.save(userRe);
|
||||
|
||||
Relationship otherRe = new Relationship();
|
||||
otherRe.setId(3);
|
||||
otherRe.setAppConfig(otherAppConfig);
|
||||
DB.save(otherRe);
|
||||
|
||||
|
||||
// Start business processing
|
||||
Query<Relationship> relationshipQuery = DB.find(Relationship.class);
|
||||
List<Relationship> relationshipList = relationshipQuery.where().idIn(1, 2, 3).findList();
|
||||
|
||||
assertThat(relationshipList.size()).isEqualTo(3);
|
||||
|
||||
Map<Integer, AppConfig> map = relationshipList.stream()
|
||||
.map(Relationship::getAppConfig)
|
||||
.map((ac) -> new AbstractMap.SimpleImmutableEntry<>(ac.getId(), ac))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
|
||||
AppConfig g = map.get(1);
|
||||
AppConfig u = map.get(2);
|
||||
AppConfig o = map.get(3);
|
||||
if (!u.getItems().isEmpty()) {
|
||||
// a source of the problem came from invoking lazy loading here
|
||||
// with the setItems call which is unnecessary due to being a ToMany
|
||||
g.setItems(u.getItems());
|
||||
}
|
||||
|
||||
assertThat(g.getItems().size()).isEqualTo(1);
|
||||
|
||||
// If this line of code is commented out, this test case will be successfully passed
|
||||
assertThat(o.getItems().size()).isEqualTo(0);
|
||||
|
||||
// org.junit.ComparisonFailure: Expected :1 Actual :2
|
||||
assertThat(g.getItems().size()).isEqualTo(1);
|
||||
|
||||
assertThat(g.getItems().get(0).getName()).isEqualTo("user");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.tests.lazyloadconf;
|
||||
|
||||
import io.ebean.annotation.Cache;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Cache(enableBeanCache = true)
|
||||
@Table(name="app_config_re")
|
||||
public class Relationship {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name="config_id",referencedColumnName="id")
|
||||
private AppConfig appConfig;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AppConfig getAppConfig() {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
public void setAppConfig(AppConfig appConfig) {
|
||||
this.appConfig = appConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class EBasicEncrypt {
|
||||
@Encrypted(dbLength = 80)
|
||||
String description;
|
||||
|
||||
@Encrypted(dbLength = 20)
|
||||
@Encrypted(dbLength = 80)
|
||||
Date dob;
|
||||
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
|
||||
@@ -59,19 +59,19 @@ public class MyEBasicConfigStartup implements ServerConfigStartup {
|
||||
@Override
|
||||
public void inserted(Object bean) {
|
||||
insertCount.incrementAndGet();
|
||||
System.out.println("-- EBasic inserted " + ((EBasic) bean).getId());
|
||||
// System.out.println("-- EBasic inserted " + ((EBasic) bean).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updated(Object bean, Set<String> updatedProperties) {
|
||||
updateCount.incrementAndGet();
|
||||
System.out.println("-- EBasic updated " + ((EBasic) bean).getId() + " updatedProperties: " + updatedProperties);
|
||||
// System.out.println("-- EBasic updated " + ((EBasic) bean).getId() + " updatedProperties: " + updatedProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleted(Object bean) {
|
||||
deleteCount.incrementAndGet();
|
||||
System.out.println("-- EBasic deleted " + ((EBasic) bean).getId());
|
||||
// System.out.println("-- EBasic deleted " + ((EBasic) bean).getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ public class Order implements Serializable {
|
||||
@DocEmbedded
|
||||
List<OrderDetail> details;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true)
|
||||
List<OrderShipment> shipments;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.tests.model.bridge;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Transaction;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -39,6 +41,28 @@ public class TestIdClassScalar extends BaseTestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertBatch() {
|
||||
UUID siteId = UUID.randomUUID();
|
||||
UUID userId = UUID.randomUUID();
|
||||
|
||||
try (final Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
|
||||
BSiteUserD access = new BSiteUserD(BAccessLevel.ONE, siteId, userId);
|
||||
DB.save(access);
|
||||
|
||||
final UUID siteId1 = access.getSiteId(); // ArrayIndexOutOfBoundsException here
|
||||
assertThat(siteId1).isNotNull();
|
||||
assertThat(access.getUserId()).isEqualTo(userId);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
DB.delete(BSiteUserD.class, new BEmbId(siteId, userId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.tests.model.m2m;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import io.ebean.annotation.Index;
|
||||
|
||||
@Entity
|
||||
@Index(unique = true, columnNames = { "from_id", "to_id" })
|
||||
@Index(unique = true, columnNames = { "to_id", "from_id" })
|
||||
public class MnyEdge {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne
|
||||
private MnyNode from;
|
||||
|
||||
@ManyToOne
|
||||
private MnyNode to;
|
||||
|
||||
private int flags;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MnyNode getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(MnyNode from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public MnyNode getTo() {
|
||||
return to;
|
||||
}
|
||||
|
||||
public void setTo(MnyNode to) {
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
public void setFlags(int flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package org.tests.model.m2m;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.Where;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class MnyNode {
|
||||
|
||||
@Id
|
||||
Integer id;
|
||||
|
||||
String name;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"))
|
||||
List<MnyNode> allRelations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"))
|
||||
List<MnyNode> allReverseRelations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"))
|
||||
@Where(clause = "${mta}.flags & 1 != 0")
|
||||
@Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = Platform.H2)
|
||||
List<MnyNode> bit1Relations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"))
|
||||
@Where(clause = "${mta}.flags & 1 != 0")
|
||||
@Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = Platform.H2)
|
||||
List<MnyNode> bit1ReverseRelations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"))
|
||||
@Where(clause = "${mta}.flags & 2 != 0")
|
||||
@Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = Platform.H2)
|
||||
List<MnyNode> bit2Relations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"))
|
||||
@Where(clause = "${mta}.flags & 2 != 0")
|
||||
@Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = Platform.H2)
|
||||
List<MnyNode> bit2ReverseRelations;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "mny_edge",
|
||||
joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"))
|
||||
@Where(clause = "'${dbTableName}' = ${ta}.name")
|
||||
List<MnyNode> withDbTableName;
|
||||
|
||||
public MnyNode() {
|
||||
|
||||
}
|
||||
|
||||
public MnyNode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<MnyNode> getAllRelations() {
|
||||
return allRelations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getAllReverseRelations() {
|
||||
return allReverseRelations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getBit1Relations() {
|
||||
return bit1Relations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getBit1ReverseRelations() {
|
||||
return bit1ReverseRelations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getBit2Relations() {
|
||||
return bit2Relations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getBit2ReverseRelations() {
|
||||
return bit2ReverseRelations;
|
||||
}
|
||||
|
||||
public List<MnyNode> getWithDbTableName() {
|
||||
return withDbTableName;
|
||||
}
|
||||
|
||||
public void setWithDbTableName(List<MnyNode> withDbTableName) {
|
||||
this.withDbTableName = withDbTableName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.tests.model.m2m;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.tests.model.m2m.MnyEdge;
|
||||
import org.tests.model.m2m.MnyNode;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebeantest.LoggedSql;
|
||||
|
||||
/**
|
||||
* Tests M2M with complex where queries.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class TestM2MWithWhere extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testQuery() throws Exception {
|
||||
createTestData();
|
||||
MnyNode node = DB.find(MnyNode.class, 1);
|
||||
|
||||
|
||||
List<MnyNode> result = DB.find(MnyNode.class).where().eq("allRelations", node).findList();
|
||||
assertThat(result).extracting(MnyNode::getId).containsExactly(1, 2, 3, 4, 5);
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("allReverseRelations", node).findList();
|
||||
assertThat(result).extracting(MnyNode::getId).containsExactly(1, 2, 3, 4, 5);
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("bit1Relations", node).findList();
|
||||
assertThat(result).isEmpty(); // -> to = 1 column: 2 0 2 0 2
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("bit2Relations", node).findList();
|
||||
assertThat(result).extracting(MnyNode::getId).containsExactly(1, 3, 5);
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("bit1ReverseRelations", node).findList();
|
||||
// -> from = 1 column: 2 1 3 1 3
|
||||
assertThat(result).extracting(MnyNode::getId).containsExactly(2, 3, 4, 5);
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("bit2ReverseRelations", node).findList();
|
||||
assertThat(result).hasSize(3).extracting(MnyNode::getId).containsExactly(1, 3, 5);
|
||||
|
||||
result = DB.find(MnyNode.class).where().eq("bit2ReverseRelations", node).findList();
|
||||
assertThat(result).hasSize(3).extracting(MnyNode::getId).containsExactly(1, 3, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetter() throws Exception {
|
||||
createTestData();
|
||||
MnyNode node = DB.find(MnyNode.class, 3);
|
||||
|
||||
assertThat(node.getAllRelations()).extracting(MnyNode::getId).containsExactly(1, 2, 3, 4, 5);
|
||||
|
||||
assertThat(node.getAllReverseRelations()).extracting(MnyNode::getId).containsExactly(1, 2, 3, 4, 5);
|
||||
|
||||
assertThat(node.getBit1Relations()).extracting(MnyNode::getId).containsExactly(4, 5);
|
||||
|
||||
assertThat(node.getBit1ReverseRelations()).extracting(MnyNode::getId).containsExactly(1, 2);
|
||||
|
||||
assertThat(node.getBit2Relations()).extracting(MnyNode::getId).containsExactly(1, 3, 5);
|
||||
|
||||
LoggedSql.start();
|
||||
assertThat(node.getBit2ReverseRelations()).extracting(MnyNode::getId).containsExactly(1, 3, 5);
|
||||
List<String> sqls = LoggedSql.stop();
|
||||
assertThat(sqls).hasSize(1); // lazy load
|
||||
|
||||
// prefetch everything
|
||||
LoggedSql.start();
|
||||
node = DB.find(MnyNode.class)
|
||||
.fetch("bit1Relations","*")
|
||||
.fetch("bit1ReverseRelations","*")
|
||||
.where().idEq(3).findOne();
|
||||
sqls = LoggedSql.stop();
|
||||
assertThat(sqls).hasSize(2);
|
||||
|
||||
// no lazyLoad expected
|
||||
LoggedSql.start();
|
||||
assertThat(node.getBit1Relations()).extracting(MnyNode::getId).containsExactly(4, 5);
|
||||
assertThat(node.getBit1ReverseRelations()).extracting(MnyNode::getId).containsExactly(1, 2);
|
||||
sqls = LoggedSql.stop();
|
||||
assertThat(sqls).hasSize(0);
|
||||
|
||||
}
|
||||
|
||||
// to = | 1 2 3 4 5
|
||||
// ---------+---------------
|
||||
// from = 1 | 2 1 3 1 3
|
||||
// from = 2 | 0 2 1 3 1
|
||||
// from = 3 | 2 0 2 1 3
|
||||
// from = 4 | 0 2 0 2 1
|
||||
// from = 5 | 2 0 2 0 2
|
||||
private void createTestData() {
|
||||
DB.find(MnyEdge.class).delete();
|
||||
DB.find(MnyNode.class).delete();
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
MnyNode node = new MnyNode();
|
||||
node.setId(i);
|
||||
node.setName("Node #" + i);
|
||||
DB.save(node);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int from = 1; from <= 5; from++) {
|
||||
sb.append("from = ").append(from).append(" |");
|
||||
for (int to = 1; to <= 5; to++) {
|
||||
MnyEdge edge = new MnyEdge();
|
||||
edge.setFrom(DB.getReference(MnyNode.class, from));
|
||||
edge.setTo(DB.getReference(MnyNode.class, to));
|
||||
int flags = 0;
|
||||
if (from < to) {
|
||||
flags |= 1;
|
||||
}
|
||||
if ((from + to) % 2 == 0) {
|
||||
flags |= 2;
|
||||
}
|
||||
edge.setFlags(flags);
|
||||
DB.save(edge);
|
||||
sb.append(" ").append(flags);
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
// System.out.println(sb); dump the table
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithDbTableName() {
|
||||
LoggedSql.start();
|
||||
DB.find(MnyNode.class).where().isNotNull("withDbTableName.name").findList();
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("'mny_node' = u1.name");
|
||||
|
||||
LoggedSql.start();
|
||||
DB.find(MnyNode.class).where().isNotEmpty("withDbTableName").findList();
|
||||
sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("'mny_node' = x2.name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoad() throws Exception {
|
||||
MnyNode el = new MnyNode("testLazyLoad");
|
||||
DB.save(el);
|
||||
LoggedSql.start();
|
||||
el = DB.find(MnyNode.class).select("name").where().eq("name", "testLazyLoad").findOne();
|
||||
el.getWithDbTableName().size(); // trigger Lazy load
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.name from mny_node");
|
||||
assertThat(sql.get(1)).contains("where 'mny_node' = t0.name");
|
||||
DB.delete(el);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.tests.model.map;
|
||||
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
public class BeanMapOrphanRemovalTest {
|
||||
|
||||
@Test
|
||||
public void keySet_retainAll() {
|
||||
|
||||
MpUser user = new MpUser();
|
||||
user.setName("u1");
|
||||
addRoles(user, "r1", "r2", "r3", "r4");
|
||||
DB.save(user);
|
||||
|
||||
final MpUser user1 = DB.find(MpUser.class, user.getId());
|
||||
final Map<String, MpRole> roles = user1.getRoles();
|
||||
assertThat(roles).hasSize(4);
|
||||
|
||||
|
||||
final Set<String> keySet = roles.keySet();
|
||||
keySet.retainAll(Arrays.asList("r2", "r3"));
|
||||
|
||||
DB.save(user1);
|
||||
|
||||
final MpUser user2 = DB.find(MpUser.class, user.getId());
|
||||
final Map<String, MpRole> roles2 = user2.getRoles();
|
||||
assertThat(roles2).hasSize(2);
|
||||
}
|
||||
|
||||
private void addRoles(MpUser user, String... roles){
|
||||
for (String code : roles) {
|
||||
MpRole role = newRole(code);
|
||||
user.getRoles().put(role.getCode(), role);
|
||||
}
|
||||
}
|
||||
|
||||
private MpRole newRole(String code) {
|
||||
MpRole role = new MpRole();
|
||||
role.setCode(code);
|
||||
return role;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,7 @@
|
||||
package org.tests.model.map;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MapKey;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.HashMap;
|
||||
import javax.persistence.*;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@@ -16,9 +12,9 @@ public class MpUser {
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@MapKey(name = "code")
|
||||
public Map<String, MpRole> roles = new HashMap<>();
|
||||
private Map<String, MpRole> roles = new LinkedHashMap<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.tests.model.onetoone.calcd;
|
||||
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.ConstraintMode;
|
||||
import io.ebean.annotation.DbForeignKey;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "calcd_data")
|
||||
public class CalcDData extends Model {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne(optional = false, cascade = CascadeType.ALL)
|
||||
@DbForeignKey(onDelete = ConstraintMode.CASCADE)
|
||||
@PrimaryKeyJoinColumn//(name = "Id", referencedColumnName = "Id")
|
||||
private CalcDInput input;
|
||||
|
||||
private final String name;
|
||||
|
||||
public CalcDData(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CalcDInput getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(CalcDInput input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.tests.model.onetoone.calcd;
|
||||
|
||||
import io.ebean.Model;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "calcd_input")
|
||||
public class CalcDInput extends Model {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@OneToOne(optional = false, fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "input")
|
||||
private CalcDData data;
|
||||
|
||||
private final String name;
|
||||
|
||||
public CalcDInput(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CalcDData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(CalcDData data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.tests.model.onetoone.calcd;
|
||||
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestOneToOnePrimaryKeyJoinMapping {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
CalcDInput inputs = new CalcDInput("input0");
|
||||
|
||||
CalcDData data = new CalcDData("data0");
|
||||
inputs.setData(data);
|
||||
inputs.save();
|
||||
|
||||
CalcDInput found = DB.find(CalcDInput.class, inputs.getId());
|
||||
|
||||
assertThat(found).isNotNull();
|
||||
assertThat(found.getName()).isEqualTo("input0");
|
||||
assertThat(found.getData().getName()).isEqualTo("data0");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelX {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@OneToOne
|
||||
private ESoftDelY y;
|
||||
|
||||
@ManyToOne
|
||||
private ESoftDelZ organization;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ESoftDelY getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(ESoftDelY y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public ESoftDelZ getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(ESoftDelZ organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelY {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private ESoftDelZ organization;
|
||||
|
||||
@OneToOne(mappedBy = "y")
|
||||
private ESoftDelX x;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ESoftDelZ getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(ESoftDelZ organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public ESoftDelX getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(ESoftDelX x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelZ {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,9 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import io.ebean.annotation.Where;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static javax.persistence.CascadeType.ALL;
|
||||
@@ -26,6 +29,10 @@ public class OmBasicParent {
|
||||
@OneToMany(cascade = ALL, mappedBy = "parent")
|
||||
private List<? extends OmBasicChild> children;
|
||||
|
||||
@OneToMany(cascade = ALL, mappedBy = "parent")
|
||||
@Where(clause = "'${dbTableName}' = ${ta}.name")
|
||||
private List<? extends OmBasicChild> childrenWithWhere;
|
||||
|
||||
public OmBasicParent(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -57,4 +64,13 @@ public class OmBasicParent {
|
||||
public void setChildren(List<? extends OmBasicChild> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
public List<? extends OmBasicChild> getChildrenWithWhere() {
|
||||
return childrenWithWhere;
|
||||
}
|
||||
|
||||
public void setChildrenWithWhere(List<? extends OmBasicChild> childrenWithWhere) {
|
||||
this.childrenWithWhere = childrenWithWhere;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.tests.o2m;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebeantest.LoggedSql;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestOneToManyWhere extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void testWithDbTableName() {
|
||||
LoggedSql.start();
|
||||
DB.find(OmBasicParent.class).where().isNotNull("childrenWithWhere.name").findList();
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("'om_basic_parent' = u1.name");
|
||||
|
||||
LoggedSql.start();
|
||||
DB.find(OmBasicParent.class).where().isNotEmpty("childrenWithWhere").findList();
|
||||
sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("'om_basic_parent' = x.name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoad() throws Exception {
|
||||
OmBasicParent el = new OmBasicParent("testLazyLoad");
|
||||
DB.save(el);
|
||||
LoggedSql.start();
|
||||
el = DB.find(OmBasicParent.class).select("name").where().eq("name", "testLazyLoad").findOne();
|
||||
el.getChildrenWithWhere().size(); // trigger Lazy load
|
||||
List<String> sql = LoggedSql.stop();
|
||||
assertThat(sql).hasSize(2);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.name from om_basic_parent");
|
||||
assertThat(sql.get(1)).contains("where 'om_basic_parent' = t0.name");
|
||||
DB.delete(el);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,11 +24,11 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase {
|
||||
query.findList();
|
||||
|
||||
if (isPostgres()) {
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id join o_order_detail u2 on u2.order_id = u1.id join o_product u3 on u3.id = u2.product_id where u3.name = ?";
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 join o_product u3 on u3.id = u2.product_id where u3.name = ?";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
|
||||
} else {
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id join o_order_detail u2 on u2.order_id = u1.id join o_product u3 on u3.id = u2.product_id where u3.name = ?";
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 join o_product u3 on u3.id = u2.product_id where u3.name = ?";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
}
|
||||
|
||||
@@ -55,10 +55,10 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase {
|
||||
query.findList();
|
||||
|
||||
if (isPostgres()) {
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null left join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
} else {
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null left join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
}
|
||||
}
|
||||
@@ -76,11 +76,11 @@ public class TestImplicitJoinOnParentRelationship extends BaseTestCase {
|
||||
query.findList();
|
||||
|
||||
if (isPostgres()) {
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
String expectedSql = "select distinct on (t0.id) t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null left join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
|
||||
} else {
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id left join o_order_detail u2 on u2.order_id = u1.id left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
String expectedSql = "select distinct t0.id, t0.name from o_customer t0 left join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null left join o_order_detail u2 on u2.order_id = u1.id and u2.id > 0 left join o_product u3 on u3.id = u2.product_id where (u3.name = ? or t0.id = ?)";
|
||||
assertThat(sqlOf(query, 1)).contains(expectedSql);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class TestManyWhereJoin extends BaseTestCase {
|
||||
}
|
||||
assertThat(sql).contains("join o_order ");
|
||||
assertThat(sql).contains(".status = ?");
|
||||
assertThat(sql).contains("t0.id, t0.status from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id where u1.status = ?");
|
||||
assertThat(sql).contains("t0.id, t0.status from o_customer t0 join o_order u1 on u1.kcustomer_id = t0.id and u1.order_date is not null where u1.status = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -172,7 +172,6 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.fetch("orders")
|
||||
.filterMany("orders").raw("1=0")
|
||||
.where().isNotEmpty("orders")
|
||||
.query();
|
||||
@@ -183,12 +182,10 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
}
|
||||
|
||||
List<String> sqlList = LoggedSqlCollector.stop();
|
||||
assertEquals(2, sqlList.size());
|
||||
assertThat(sqlList.get(0)).contains("where exists (select 1 from o_order x where x.kcustomer_id = t0.id)");
|
||||
assertThat(sqlList.get(1)).contains("and 1=0");
|
||||
assertEquals(1, sqlList.size());
|
||||
assertThat(sqlList.get(0)).contains("from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where exists (select 1 from o_order x where x.kcustomer_id = t0.id and x.order_date is not null) and 1=0 order by t0.id");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void test_filterMany_in_findCount() {
|
||||
|
||||
@@ -212,7 +209,6 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
public void test_filterMany_copy_findList() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
@@ -222,17 +218,35 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
|
||||
query.copy().findList();
|
||||
|
||||
List<String> sqlList = LoggedSqlCollector.stop();
|
||||
assertEquals(1, sqlList.size());
|
||||
assertThat(sqlList.get(0)).contains("from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where t1.status in (?) order by t0.id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterMany_fetchQuery() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Query<Customer> query = Ebean.find(Customer.class)
|
||||
.fetchQuery("orders") // explicitly fetch orders separately
|
||||
.filterMany("orders").in("status", Order.Status.NEW)
|
||||
.order().asc("id");
|
||||
|
||||
query.findList();
|
||||
|
||||
List<String> sqlList = LoggedSqlCollector.stop();
|
||||
assertEquals(2, sqlList.size());
|
||||
assertThat(sqlList.get(0)).contains("from o_customer t0");
|
||||
assertThat(sqlList.get(1)).contains("from o_order t0 join o_customer t1");
|
||||
assertThat(sqlList.get(1)).contains("from o_order t0 join o_customer t1 on t1.id = t0.kcustomer_id where t0.order_date is not null and (t0.kcustomer_id) in ");
|
||||
assertThat(sqlList.get(1)).contains(" and t0.status in ");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisjunction() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Ebean.find(Customer.class)
|
||||
@@ -243,8 +257,8 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
.findList();
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
assertEquals(2, sql.size());
|
||||
assertSql(sql.get(1)).contains("and (t0.status = ? or t0.order_date = ?");
|
||||
assertEquals(1, sql.size());
|
||||
assertSql(sql.get(0)).contains(" from o_customer t0 left join o_order t1 on t1.kcustomer_id = t0.id and t1.order_date is not null left join o_customer t2 on t2.id = t1.kcustomer_id where (t1.status = ? or t1.order_date = ?) order by t0.id");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -259,12 +273,10 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql).hasSize(3);
|
||||
assertSql(sql.get(0)).contains(" from o_customer t0; --bind()");
|
||||
platformAssertIn(sql.get(1), " from contact t0 where (t0.customer_id)");
|
||||
assertSql(sql.get(1)).contains(" and t0.first_name is not null");
|
||||
platformAssertIn(sql.get(2), " from contact_note t0 where (t0.contact_id)");
|
||||
assertSql(sql.get(2)).contains(" and lower(t0.title) like");
|
||||
assertThat(sql).hasSize(2);
|
||||
assertSql(sql.get(0)).contains(" from o_customer t0 left join contact t1 on t1.customer_id = t0.id where t1.first_name is not null order by t0.id; --bind()");
|
||||
platformAssertIn(sql.get(1), " from contact_note t0 where (t0.contact_id)");
|
||||
assertSql(sql.get(1)).contains(" and lower(t0.title) like");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -280,9 +292,7 @@ public class TestQueryFilterMany extends BaseTestCase {
|
||||
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(sql).hasSize(2);
|
||||
assertSql(sql.get(0)).contains(" from o_customer t0");
|
||||
assertSql(sql.get(1)).contains("from contact t0 where ");
|
||||
assertSql(sql.get(1)).contains("and (t0.first_name is not null and lower(t0.email) like ?");
|
||||
assertThat(sql).hasSize(1);
|
||||
assertSql(sql.get(0)).contains(" from o_customer t0 left join contact t1 on t1.customer_id = t0.id where (t1.first_name is not null and lower(t1.email) like ? escape'|' ) order by t0.id; --bind(rob%)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,7 @@ public class TestQueryFindStream extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void findLargeStream_basic() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
try (Stream<Customer> stream = DB.find(Customer.class)
|
||||
.findLargeStream()) {
|
||||
|
||||
@@ -61,8 +59,16 @@ public class TestQueryFindStream extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void manualTest_findSteam_when_streamNotClosed_connectionLeak() {
|
||||
public void manualTest_findSteam_when_closeWithResources() {
|
||||
// confirm manually the stream is closed via try with resources block
|
||||
try (Stream<Customer> stream = DB.find(Customer.class).findStream()) {
|
||||
// silly assert
|
||||
assertThat(stream.hashCode()).isNotZero();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void manualTest_findSteam_when_streamNotClosed_connectionLeak() {
|
||||
Stream<Customer> stream = DB.find(Customer.class).findStream();
|
||||
// remember a steam MUST be closed or we leak resources
|
||||
// comment out the close(); below to leak a connection
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package org.tests.query;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Query;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.ResetBasicData;
|
||||
import org.tests.model.m2m.Role;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestQueryIsNull extends BaseTestCase {
|
||||
|
||||
@@ -17,90 +18,90 @@ public class TestQueryIsNull extends BaseTestCase {
|
||||
public void queryShouldContainIsNullOnColumn() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).where().isNull("customerName").query();
|
||||
Query<Order> query = DB.find(Order.class).where().isNull("customerName").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains("name is null"));
|
||||
assertThat(query.getGeneratedSql()).contains("name is null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotNull_when_OneToMany_expect_existsSubquery() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).where().isNotNull("details").query();
|
||||
Query<Order> query = DB.find(Order.class).where().isNotNull("details").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains(" where exists (select 1 from o_order_detail x where x.order_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains(" where exists (select 1 from o_order_detail x where x.order_id = t0.id and x.id > 0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmpty_when_OneToMany_expect_existsSubquery() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).where().isNotEmpty("details").query();
|
||||
Query<Order> query = DB.find(Order.class).where().isNotEmpty("details").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains(" where exists (select 1 from o_order_detail x where x.order_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains(" where exists (select 1 from o_order_detail x where x.order_id = t0.id and x.id > 0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNull_when_OneToMany_expect_notExistsSubquery() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).where().isNull("details").query();
|
||||
Query<Order> query = DB.find(Order.class).where().isNull("details").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains(" where not exists (select 1 from o_order_detail x where x.order_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains(" where not exists (select 1 from o_order_detail x where x.order_id = t0.id and x.id > 0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmpty_when_OneToMany_expect_notExistsSubquery() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class).where().isEmpty("details").query();
|
||||
Query<Order> query = DB.find(Order.class).where().isEmpty("details").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains(" where not exists (select 1 from o_order_detail x where x.order_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains(" where not exists (select 1 from o_order_detail x where x.order_id = t0.id and x.id > 0)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEmpty_when_ManyToMany_expect_notExistsSubqueryAndNoJoin() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Role> query = Ebean.find(Role.class).where().isEmpty("permissions").query();
|
||||
Query<Role> query = DB.find(Role.class).where().isEmpty("permissions").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains("from mt_role t0 where not exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains("from mt_role t0 where not exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNull_when_ManyToMany_expect_notExistsSubqueryAndNoJoin() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Role> query = Ebean.find(Role.class).where().isNull("permissions").query();
|
||||
Query<Role> query = DB.find(Role.class).where().isNull("permissions").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains("from mt_role t0 where not exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains("from mt_role t0 where not exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotEmpty_when_ManyToMany_expect_existsSubqueryAndNoJoin() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Role> query = Ebean.find(Role.class).where().isNotEmpty("permissions").query();
|
||||
Query<Role> query = DB.find(Role.class).where().isNotEmpty("permissions").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains("from mt_role t0 where exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains("from mt_role t0 where exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isNotNull_when_ManyToMany_expect_existsSubqueryAndNoJoin() {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Query<Role> query = Ebean.find(Role.class).where().isNotNull("permissions").query();
|
||||
Query<Role> query = DB.find(Role.class).where().isNotNull("permissions").query();
|
||||
query.findList();
|
||||
|
||||
assertTrue(query.getGeneratedSql().contains("from mt_role t0 where exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)"));
|
||||
assertThat(query.getGeneratedSql()).contains("from mt_role t0 where exists (select 1 from mt_role_permission x where x.mt_role_id = t0.id)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.tests.query.cancel;
|
||||
|
||||
import org.tests.model.basic.EBasic.Status;
|
||||
|
||||
/**
|
||||
* DTO for Ebasic Queries.
|
||||
*/
|
||||
public class EBasicDto {
|
||||
private Integer id;
|
||||
|
||||
private Status status;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.tests.query.cancel;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import org.h2.api.Trigger;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Transaction;
|
||||
|
||||
/**
|
||||
* Class to artificially slow down selects on 'e_basic' table
|
||||
*/
|
||||
public class SlowDownEBasic implements Trigger {
|
||||
|
||||
private static int wait;
|
||||
|
||||
private static boolean triggerInstalled;
|
||||
|
||||
@Override
|
||||
public void init(final Connection conn, final String schemaName, final String triggerName, final String tableName,
|
||||
final boolean before, final int type) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fire(final Connection conn, final Object[] oldRow, final Object[] newRow) {
|
||||
try {
|
||||
Thread.sleep(wait);
|
||||
} catch (InterruptedException e) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
|
||||
public static void setSelectWaitMillis(final int wait) throws SQLException {
|
||||
SlowDownEBasic.wait = wait;
|
||||
if (triggerInstalled) {
|
||||
return;
|
||||
}
|
||||
triggerInstalled = true;
|
||||
try (Transaction txn = DB.beginTransaction(); Statement stmt = txn.getConnection().createStatement()) {
|
||||
|
||||
stmt.execute("CREATE TRIGGER SLOW_DOWN_E_BASIC BEFORE SELECT ON e_basic " + "CALL \""
|
||||
+ SlowDownEBasic.class.getName() + "\"");
|
||||
txn.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
package org.tests.query.cancel;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EBasic;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.DtoQuery;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.QueryIterator;
|
||||
import io.ebean.SqlQuery;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
/**
|
||||
* Tests, if all kind of queries are cancelable. There are two ways how to
|
||||
* cancel a query: <br/>
|
||||
* <b>At begin:</b>
|
||||
*
|
||||
* <pre>
|
||||
* query = DB.find(...)
|
||||
* query.cancel();
|
||||
* query.findList();
|
||||
* </pre>
|
||||
*
|
||||
* The query was caneled before executing. In this case we do hit the DB driver
|
||||
* <br/>
|
||||
* <br/>
|
||||
* <b>During run:</b>
|
||||
*
|
||||
* <pre>
|
||||
* // Thread 1: Thread 2
|
||||
* query = DB.find(...)
|
||||
* query.findList();
|
||||
* ...finding
|
||||
* ...finding query.cancel();
|
||||
* ...JDBC-Exception
|
||||
* </pre>
|
||||
*
|
||||
* The test tries to simulate a slow query by installing the
|
||||
* {@link SlowDownEBasic} 'SELECT' trigger. The trigger can be configured to
|
||||
* wait 3 * <code>timing</code> ms and a second thread will cancel the query in
|
||||
* <code>timing</code> ms.
|
||||
*
|
||||
* in this case, we expect a JDBC exception from the driver. <br/>
|
||||
* <br/>
|
||||
* NOTE:<br/>
|
||||
* H2 checks the cancel flag in org.h2.command.Prepared::setCurrentRowNumber
|
||||
* only every 128th row. So we need at least 128 models and we cannot check
|
||||
* queries like findCount or findOne, because they only return one row.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class SqlQueryCancelTest extends BaseTestCase {
|
||||
|
||||
private int timing = 10;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupTestData() throws SQLException {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
EBasic model = new EBasic("Basic " + i);
|
||||
DB.save(model);
|
||||
}
|
||||
SlowDownEBasic.setSelectWaitMillis(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelSqlQueryAtBegin() throws SQLException {
|
||||
doCancelSqlAtBegin(SqlQuery::findList);
|
||||
doCancelSqlAtBegin(SqlQuery::findOne);
|
||||
doCancelSqlAtBegin(q -> q.findEach(e -> {}));
|
||||
doCancelSqlAtBegin(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void cancelSqlDuringRun() throws SQLException {
|
||||
|
||||
doCancelSqlDuringRun(SqlQuery::findList);
|
||||
// doCancelSqlDuringRun(q -> q.setMaxRows(1).findOne());
|
||||
// findOne cannot be tested, as H2 does the cancel check every 128 rows only
|
||||
doCancelSqlDuringRun(q -> q.findEach(e -> {}));
|
||||
doCancelSqlDuringRun(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void cancelOrmQueryAtBegin() throws SQLException {
|
||||
doCancelOrmAtBegin(Query::findCount);
|
||||
doCancelOrmAtBegin(Query::findFutureCount);
|
||||
// We cannot test 'findCount' due H2 restrictions
|
||||
doCancelOrmAtBegin(Query::findFutureIds);
|
||||
doCancelOrmAtBegin(Query::findFutureList);
|
||||
doCancelOrmAtBegin(Query::findIds);
|
||||
doCancelOrmAtBegin(Query::findIterate);
|
||||
doCancelOrmAtBegin(Query::findList);
|
||||
doCancelOrmAtBegin(Query::findMap);
|
||||
doCancelOrmAtBegin(Query::findOne);
|
||||
doCancelOrmAtBegin(q -> q.setMaxRows(1000).findPagedList().getList()); // untested
|
||||
doCancelOrmAtBegin(Query::findSet);
|
||||
doCancelOrmAtBegin(Query::findSingleAttribute);
|
||||
doCancelOrmAtBegin(Query::findSingleAttributeList);
|
||||
doCancelOrmAtBegin(Query::findStream);
|
||||
// testDuringRun(Query::findVersions);
|
||||
// EBasic has no history support, but it should work if @History is added
|
||||
doCancelOrmAtBegin(q -> q.findEach(e -> {}));
|
||||
doCancelOrmAtBegin(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void cancelOrmDuringRun() throws Throwable {
|
||||
// doCancelOrmDuringRun(Query::findCount);
|
||||
// testDuringRunFuture(Query::findFutureCount);
|
||||
// We cannot test 'findCount' due H2 restrictions
|
||||
doCancelOrmFutureDuringRun(Query::findFutureIds);
|
||||
doCancelOrmFutureDuringRun(Query::findFutureList);
|
||||
doCancelOrmDuringRun(Query::findIds);
|
||||
doCancelOrmDuringRun(Query::findIterate);
|
||||
doCancelOrmDuringRun(Query::findList);
|
||||
doCancelOrmDuringRun(Query::findMap);
|
||||
// doCancelOrmDuringRun(q -> q.setMaxRows(1).findOne());
|
||||
// findOne cannot be tested, as H2 does the cancel check every 128 rows only
|
||||
doCancelOrmDuringRun(q -> q.setMaxRows(1000).findPagedList().getList()); // untested
|
||||
doCancelOrmDuringRun(Query::findSet);
|
||||
doCancelOrmDuringRun(Query::findSingleAttribute);
|
||||
doCancelOrmDuringRun(Query::findSingleAttributeList);
|
||||
doCancelOrmDuringRun(Query::findStream);
|
||||
// testDuringRun(Query::findVersions);
|
||||
// EBasic has no history support, but it should work if @History is added
|
||||
doCancelOrmDuringRun(q -> q.findEach(e -> {}));
|
||||
doCancelOrmDuringRun(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelOrmDuringIterate() throws SQLException {
|
||||
|
||||
Query<EBasic> query = DB.find(EBasic.class);
|
||||
|
||||
QueryIterator<EBasic> iter = query.findIterate();
|
||||
assertThat(iter.hasNext()).isTrue();
|
||||
query.cancel();
|
||||
assertThat(iter.next()).isNotNull();
|
||||
|
||||
// We might have 100 entities in a buffer. So we must iterate through all.
|
||||
assertThatThrownBy(() -> {
|
||||
while(iter.hasNext()) iter.next();
|
||||
})
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelOrmDtoQueryAtBegin() throws SQLException {
|
||||
|
||||
doCancelOrmDtoAtBegin(DtoQuery::findIterate);
|
||||
doCancelOrmDtoAtBegin(DtoQuery::findList);
|
||||
doCancelOrmDtoAtBegin(DtoQuery::findOne);
|
||||
doCancelOrmDtoAtBegin(DtoQuery::findStream);
|
||||
doCancelOrmDtoAtBegin(q -> q.findEach(e -> {}));
|
||||
doCancelOrmDtoAtBegin(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void cancelOrmDtoDuringRun() throws SQLException {
|
||||
|
||||
doCancelOrmDtoDuringRun(DtoQuery::findIterate);
|
||||
doCancelOrmDtoDuringRun(DtoQuery::findList);
|
||||
// doCancelOrmDtoDuringRun(q -> q.setMaxRows(1).findOne());
|
||||
// findOne cannot be tested, as H2 does the cancel check every 128 rows only
|
||||
doCancelOrmDtoDuringRun(DtoQuery::findStream);
|
||||
doCancelOrmDtoDuringRun(q -> q.findEach(e -> {}));
|
||||
doCancelOrmDtoDuringRun(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelOrmDtoDuringIterate() throws SQLException {
|
||||
|
||||
DtoQuery<EBasicDto> query = DB.find(EBasic.class).select("id,status").asDto(EBasicDto.class);
|
||||
|
||||
QueryIterator<EBasicDto> iter = query.findIterate();
|
||||
assertThat(iter.hasNext()).isTrue();
|
||||
query.cancel();
|
||||
assertThat(iter.next()).isNotNull();
|
||||
|
||||
// We might have 100 entities in a buffer. So we must iterate through all.
|
||||
assertThatThrownBy(() -> {
|
||||
while(iter.hasNext()) iter.next();
|
||||
})
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelSqlDtoQueryAtBegin() throws SQLException {
|
||||
|
||||
doCancelSqlDtoAtBegin(DtoQuery::findIterate);
|
||||
doCancelSqlDtoAtBegin(DtoQuery::findList);
|
||||
doCancelSqlDtoAtBegin(DtoQuery::findOne);
|
||||
doCancelSqlDtoAtBegin(DtoQuery::findStream);
|
||||
doCancelSqlDtoAtBegin(q -> q.findEach(e -> {}));
|
||||
doCancelSqlDtoAtBegin(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void cancelSqlDtoDuringRun() throws SQLException {
|
||||
|
||||
//doCancelSqlDtoDuringRun(DtoQuery::findIterate);
|
||||
doCancelSqlDtoDuringRun(DtoQuery::findList);
|
||||
// doCancelSqlDtoDuringRun(q -> q.setMaxRows(1).findOne());
|
||||
// findOne cannot be tested, as H2 does the cancel check every 128 rows only
|
||||
doCancelSqlDtoDuringRun(DtoQuery::findStream);
|
||||
doCancelSqlDtoDuringRun(q -> q.findEach(e -> {}));
|
||||
doCancelSqlDtoDuringRun(q -> q.findEachWhile(e -> true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cancelSqlDtoDuringIterate() throws SQLException {
|
||||
|
||||
DtoQuery<EBasicDto> query = DB.findDto(EBasicDto.class, "select id, status from e_basic");
|
||||
|
||||
QueryIterator<EBasicDto> iter = query.findIterate();
|
||||
assertThat(iter.hasNext()).isTrue();
|
||||
query.cancel();
|
||||
assertThat(iter.next()).isNotNull();
|
||||
|
||||
// We might have 100 entities in a buffer. So we must iterate through all.
|
||||
assertThatThrownBy(() -> {
|
||||
while(iter.hasNext()) iter.next();
|
||||
})
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
private void doCancelSqlAtBegin(Consumer<SqlQuery> test) throws SQLException {
|
||||
SqlQuery query = DB.sqlQuery("select * from e_basic");
|
||||
query.cancel();
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
private void doCancelSqlDuringRun(Consumer<SqlQuery> test) throws SQLException {
|
||||
SqlQuery warmup = DB.sqlQuery("select * from e_basic");
|
||||
test.accept(warmup);
|
||||
SqlQuery query = DB.sqlQuery("select * from e_basic");
|
||||
executeDelayed(query::cancel);
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasCauseInstanceOf(org.h2.jdbc.JdbcSQLTimeoutException.class);
|
||||
}
|
||||
|
||||
private void doCancelOrmAtBegin(Consumer<Query<EBasic>> test) throws SQLException {
|
||||
Query<EBasic> query = DB.find(EBasic.class);
|
||||
query.cancel();
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
private void doCancelOrmDuringRun(Consumer<Query<EBasic>> test) throws SQLException {
|
||||
Query<EBasic> warmup = DB.find(EBasic.class);
|
||||
test.accept(warmup);
|
||||
Query<EBasic> warmup2 = DB.find(EBasic.class);
|
||||
test.accept(warmup2);
|
||||
Query<EBasic> query = DB.find(EBasic.class);
|
||||
executeDelayed(query::cancel);
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasCauseInstanceOf(org.h2.jdbc.JdbcSQLTimeoutException.class);
|
||||
}
|
||||
|
||||
private void doCancelOrmFutureDuringRun(Function<Query<EBasic>, Future<?>> test) throws SQLException, InterruptedException, ExecutionException {
|
||||
Query<EBasic> warmup = DB.find(EBasic.class);
|
||||
test.apply(warmup).get();
|
||||
|
||||
Query<EBasic> query = DB.find(EBasic.class);
|
||||
executeDelayed(query::cancel);
|
||||
assertThatThrownBy(() -> {
|
||||
try {
|
||||
test.apply(query).get();
|
||||
} catch (ExecutionException ee) {
|
||||
throw ee.getCause();
|
||||
}
|
||||
})
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasCauseInstanceOf(org.h2.jdbc.JdbcSQLTimeoutException.class);
|
||||
}
|
||||
|
||||
private void doCancelOrmDtoAtBegin(Consumer<DtoQuery<EBasicDto>> test) throws SQLException {
|
||||
DtoQuery<EBasicDto> query = DB.find(EBasic.class).select("id,status").asDto(EBasicDto.class);
|
||||
query.cancel();
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
private void doCancelOrmDtoDuringRun(Consumer<DtoQuery<EBasicDto>> test) throws SQLException {
|
||||
DtoQuery<EBasicDto> warmup = DB.find(EBasic.class).select("id,status").asDto(EBasicDto.class);
|
||||
test.accept(warmup);
|
||||
|
||||
DtoQuery<EBasicDto> query = DB.find(EBasic.class).select("id,status").asDto(EBasicDto.class);
|
||||
executeDelayed(query::cancel);
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasCauseInstanceOf(org.h2.jdbc.JdbcSQLTimeoutException.class);
|
||||
}
|
||||
|
||||
private void doCancelSqlDtoAtBegin(Consumer<DtoQuery<EBasicDto>> test) throws SQLException {
|
||||
DtoQuery<EBasicDto> query = DB.findDto(EBasicDto.class, "select id, status from e_basic");
|
||||
query.cancel();
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasMessageContaining("Query was cancelled");
|
||||
}
|
||||
|
||||
private void doCancelSqlDtoDuringRun(Consumer<DtoQuery<EBasicDto>> test) throws SQLException {
|
||||
DtoQuery<EBasicDto> warmup = DB.findDto(EBasicDto.class, "select id, status from e_basic");
|
||||
test.accept(warmup);
|
||||
|
||||
DtoQuery<EBasicDto> query = DB.findDto(EBasicDto.class, "select id, status from e_basic");
|
||||
executeDelayed(query::cancel);
|
||||
assertThatThrownBy(() -> test.accept(query))
|
||||
.isInstanceOf(PersistenceException.class)
|
||||
.hasCauseInstanceOf(org.h2.jdbc.JdbcSQLTimeoutException.class);
|
||||
}
|
||||
|
||||
private void executeDelayed(Runnable r) throws SQLException {
|
||||
// We modify the DB here. Otherwise we may hit an internal H2 cache, if the
|
||||
// same query is performed. Queries from the cache cannot be canceled.
|
||||
EBasic makeDbDirty = new EBasic("Basic " + UUID.randomUUID());
|
||||
DB.save(makeDbDirty);
|
||||
SlowDownEBasic.setSelectWaitMillis(timing * 3);
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(timing);
|
||||
r.run();
|
||||
SlowDownEBasic.setSelectWaitMillis(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import io.ebean.Ebean;
|
||||
import io.ebean.Expr;
|
||||
import io.ebean.Query;
|
||||
import org.junit.Test;
|
||||
import org.tests.basic.one2one.Wheel;
|
||||
import org.tests.model.basic.MRole;
|
||||
import org.tests.model.basic.MUser;
|
||||
|
||||
@@ -82,6 +83,24 @@ public class TestDisjunctWhereOuterJoin extends BaseTestCase {
|
||||
assertThat(sql).contains("where (t0.user_name = ? or u1.roleid = ?)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectOneToOneDisjunction() {
|
||||
Ebean.beginTransaction();
|
||||
try {
|
||||
Query<Wheel> query = Ebean.find(Wheel.class)
|
||||
.select("id")
|
||||
.where().or()
|
||||
.ge("tire.id", 100)
|
||||
.lt("tire.id", 100)
|
||||
.endOr().query();
|
||||
query.findList();
|
||||
String sql = sqlOf(query);
|
||||
assertThat(sql).contains("join");
|
||||
} finally {
|
||||
Ebean.rollbackTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private void queryOrExpression(Integer roleid) {
|
||||
|
||||
Query<MUser> query = Ebean.find(MUser.class)
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.tests.query.lazy;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.ProfileLocation;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.OrderDetail;
|
||||
@@ -13,12 +14,18 @@ import java.util.List;
|
||||
|
||||
public class TestQueryDefaultBatchSize extends BaseTestCase {
|
||||
|
||||
private static final ProfileLocation loc0 = ProfileLocation.create();
|
||||
private static final ProfileLocation loc1 = ProfileLocation.create();
|
||||
private static final ProfileLocation loc2 = ProfileLocation.create();
|
||||
private static final ProfileLocation loc3 = ProfileLocation.create();
|
||||
|
||||
@Test
|
||||
public void test_findEach() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
Ebean.find(Order.class)
|
||||
.setProfileLocation(loc0)
|
||||
.setLazyLoadBatchSize(2)
|
||||
.findEach(bean -> doStuff(bean));
|
||||
}
|
||||
@@ -29,6 +36,7 @@ public class TestQueryDefaultBatchSize extends BaseTestCase {
|
||||
ResetBasicData.reset();
|
||||
|
||||
Ebean.find(Order.class)
|
||||
.setProfileLocation(loc1)
|
||||
.fetch("details", "id")
|
||||
.fetch("details.product", "sku")
|
||||
.fetch("customer")
|
||||
@@ -44,6 +52,7 @@ public class TestQueryDefaultBatchSize extends BaseTestCase {
|
||||
|
||||
List<Order> orders =
|
||||
Ebean.find(Order.class)
|
||||
.setProfileLocation(loc2)
|
||||
.setLazyLoadBatchSize(2)
|
||||
.findList();
|
||||
|
||||
@@ -59,6 +68,7 @@ public class TestQueryDefaultBatchSize extends BaseTestCase {
|
||||
|
||||
List<Order> orders =
|
||||
Ebean.find(Order.class)
|
||||
.setProfileLocation(loc3)
|
||||
.fetch("details", "id")
|
||||
.fetch("details.product", "sku")
|
||||
.fetch("customer")
|
||||
|
||||
@@ -30,6 +30,6 @@ public class TestQueryRawExpressionMany extends BaseTestCase {
|
||||
query.findCount();
|
||||
List<String> sql = LoggedSqlCollector.stop();
|
||||
|
||||
assertThat(trimSql(sql.get(0), 1)).contains("select count(*) from ( select distinct t0.id from o_order t0 left join o_order_detail t1 on t1.order_id = t0.id where t1.order_qty = ?)");
|
||||
assertThat(trimSql(sql.get(0), 1)).contains("select count(*) from ( select distinct t0.id from o_order t0 left join o_order_detail t1 on t1.order_id = t0.id and t1.id > 0 where t1.order_qty = ?)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class TestQueryRowCountWithMany extends BaseTestCase {
|
||||
assertEquals(list.size(), rowCount);
|
||||
assertEquals(2, sqlLogged.size());
|
||||
assertThat(trimSql(sqlLogged.get(1), 1)).contains(
|
||||
"select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ?)");
|
||||
"select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id and u1.id > 0 where u1.product_id = ?)");
|
||||
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class TestQueryRowCountWithMany extends BaseTestCase {
|
||||
List<String> sqlLogged = LoggedSqlCollector.stop();
|
||||
|
||||
assertEquals(1, sqlLogged.size());
|
||||
assertThat(trimSql(sqlLogged.get(0), 1)).contains("select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id where u1.product_id = ?)");
|
||||
assertThat(trimSql(sqlLogged.get(0), 1)).contains("select count(*) from ( select distinct t0.id from o_order t0 join o_order_detail u1 on u1.order_id = t0.id and u1.id > 0 where u1.product_id = ?)");
|
||||
|
||||
query.findList();
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class TestQuerySingleAttribute extends BaseTestCase {
|
||||
|
||||
assertThat(sqlOf(query)).contains("select r1.attribute_, count(*) " +
|
||||
"from (select distinct t0.id, t0.name as attribute_ " +
|
||||
"from o_customer t0 left join contact u1 on u1.customer_id = t0.id left join o_order u2 on u2.kcustomer_id = t0.id " +
|
||||
"from o_customer t0 left join contact u1 on u1.customer_id = t0.id left join o_order u2 on u2.kcustomer_id = t0.id and u2.order_date is not null " +
|
||||
"where t0.name = ? and (u2.status = ? or u1.first_name = ?)) r1 " +
|
||||
"group by r1.attribute_ " +
|
||||
"order by count(*) desc, r1.attribute_");
|
||||
|
||||
@@ -2,10 +2,11 @@ package org.tests.query.sqlquery;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.RowMapper;
|
||||
import io.ebean.SqlQuery;
|
||||
import io.ebean.SqlRow;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.meta.MetaTimedMetric;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
@@ -25,6 +26,19 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class SqlQueryTests extends BaseTestCase {
|
||||
|
||||
@ForPlatform(Platform.H2)
|
||||
@Test
|
||||
public void selectFunction() {
|
||||
|
||||
String sql = "select length(?)";
|
||||
final Long val = DB.sqlQuery(sql).setParameter("NotVeryLong").mapToScalar(Long.class).findOne();
|
||||
assertThat(val).isEqualTo(11);
|
||||
|
||||
String sql2 = "select length(:val)";
|
||||
final Long val2 = DB.sqlQuery(sql2).setParameter("val", "NotVeryLong").mapToScalar(Long.class).findOne();
|
||||
assertThat(val2).isEqualTo(11);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSingleAttributeList_decimal() {
|
||||
|
||||
@@ -40,6 +54,28 @@ public class SqlQueryTests extends BaseTestCase {
|
||||
assertThat(lineAmounts).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSingleAttributeEach_decimal() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
String sql = "select (unit_price * order_qty) from o_order_detail where unit_price > ? order by (unit_price * order_qty) desc";
|
||||
|
||||
AtomicLong counter = new AtomicLong();
|
||||
AtomicLong inc = new AtomicLong();
|
||||
|
||||
DB.sqlQuery(sql)
|
||||
.setParameter(3)
|
||||
.mapToScalar(BigDecimal.class)
|
||||
.findEach(val -> {
|
||||
counter.incrementAndGet();
|
||||
inc.addAndGet(val.longValue());
|
||||
});
|
||||
|
||||
assertThat(inc.get()).isGreaterThan(counter.get());
|
||||
assertThat(counter.get()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSingleDecimal() {
|
||||
|
||||
@@ -142,6 +178,24 @@ public class SqlQueryTests extends BaseTestCase {
|
||||
|
||||
private static final CustMapper CUST_MAPPER = new CustMapper();
|
||||
|
||||
@Test
|
||||
public void findEach_mapper() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
String sql = "select id, name, status from o_customer where name is not null";
|
||||
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
DB.sqlQuery(sql)
|
||||
.mapTo(CUST_MAPPER)
|
||||
.findEach(custDto -> {
|
||||
counter.incrementAndGet();
|
||||
assertThat(custDto.name).isNotNull();
|
||||
});
|
||||
|
||||
assertThat(counter.get()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOne_mapper() {
|
||||
|
||||
@@ -361,7 +415,7 @@ public class SqlQueryTests extends BaseTestCase {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
int expectedRows = Ebean.find(Order.class).findCount();
|
||||
int expectedRows = DB.find(Order.class).findCount();
|
||||
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
package org.tests.softdelete;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.tests.model.softdelete.ESoftDelMid;
|
||||
import io.ebean.Finder;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.softdelete.ESoftDelY;
|
||||
import org.tests.model.softdelete.ESoftDelZ;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -24,5 +32,35 @@ public class TestSoftDeleteOptionalRelationship extends BaseTestCase {
|
||||
assertThat(bean.getTop()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindNullWhenMultiple() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
{
|
||||
ESoftDelZ z = new ESoftDelZ();
|
||||
z.setUuid(uuid);
|
||||
DB.save(z);
|
||||
|
||||
ESoftDelY y = new ESoftDelY();
|
||||
y.setOrganization(z);
|
||||
y.setX(null);
|
||||
DB.save(y);
|
||||
}
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
Finder<Long, ESoftDelY> finder = new Finder<>(ESoftDelY.class);
|
||||
ESoftDelY bean = finder
|
||||
.query()
|
||||
.where()
|
||||
.eq("organization.uuid", uuid)
|
||||
.isNull("x")
|
||||
.findOne();
|
||||
|
||||
assertThat(bean).isNotNull();
|
||||
|
||||
final List<String> sql = LoggedSqlCollector.stop();
|
||||
assertThat(sql).hasSize(1);
|
||||
assertThat(sql.get(0)).contains("left join esoft_del_z t1 on t1.id = t0.organization_id and t1.deleted = false where");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.tests.transaction;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.TransactionCallbackAdapter;
|
||||
import org.junit.Test;
|
||||
@@ -18,20 +17,12 @@ public class TestTransactionCallback extends BaseTestCase {
|
||||
int countPreRollback;
|
||||
int countPostRollback;
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void test_noActiveTransaction() {
|
||||
|
||||
Ebean.register(new MyCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_commitAndRollback() {
|
||||
|
||||
|
||||
try (Transaction txn = Ebean.beginTransaction()) {
|
||||
Ebean.register(new MyCallback());
|
||||
txn.getConnection();
|
||||
Ebean.commitTransaction();
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
DB.register(new MyCallback());
|
||||
txn.getConnection(); // Ebean assumes writes have occurred
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
assertEquals(1, countPreCommit);
|
||||
@@ -39,28 +30,54 @@ public class TestTransactionCallback extends BaseTestCase {
|
||||
assertEquals(0, countPreRollback);
|
||||
assertEquals(0, countPostRollback);
|
||||
|
||||
Ebean.beginTransaction();
|
||||
DB.beginTransaction();
|
||||
try {
|
||||
Ebean.register(new MyCallback());
|
||||
DB.register(new MyCallback());
|
||||
} finally {
|
||||
Ebean.rollbackTransaction();
|
||||
DB.rollbackTransaction();
|
||||
}
|
||||
|
||||
assertEquals(1, countPreCommit);
|
||||
assertEquals(1, countPostCommit);
|
||||
assertEquals(1, countPreRollback);
|
||||
assertEquals(1, countPostRollback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_commit_whenNoDbWrite() {
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
DB.register(new MyCallback());
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
assertEquals(1, countPreCommit);
|
||||
assertEquals(1, countPostCommit);
|
||||
assertEquals(0, countPreRollback);
|
||||
assertEquals(0, countPostRollback);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_rollback_whenNoDbWrite() {
|
||||
try (Transaction txn = DB.beginTransaction()) {
|
||||
DB.register(new MyCallback());
|
||||
txn.rollback();
|
||||
}
|
||||
|
||||
assertEquals(0, countPreCommit);
|
||||
assertEquals(0, countPostCommit);
|
||||
assertEquals(1, countPreRollback);
|
||||
assertEquals(1, countPostRollback);
|
||||
}
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void test_withEbeanserver() {
|
||||
|
||||
EbeanServer server = Ebean.getServer(null);
|
||||
server.register(new MyCallback());
|
||||
public void test_noActiveTransaction() {
|
||||
DB.register(new MyCallback());
|
||||
}
|
||||
|
||||
@Test(expected = PersistenceException.class)
|
||||
public void test_noActiveTransaction_withDatabase() {
|
||||
DB.getDefault().register(new MyCallback());
|
||||
}
|
||||
|
||||
class MyCallback extends TransactionCallbackAdapter {
|
||||
|
||||
|
||||
@@ -2,12 +2,15 @@ package org.tests.transparentpersist;
|
||||
|
||||
import io.ebean.*;
|
||||
import io.ebean.annotation.*;
|
||||
import io.ebeaninternal.api.SpiBeanTypeManager;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeantest.LoggedSql;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.basic.Order;
|
||||
import org.tests.model.basic.OrderShipment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -181,6 +184,8 @@ public class TestTransparentPersist extends BaseTestCase {
|
||||
Order order = new Order();
|
||||
order.setStatus(Order.Status.NEW);
|
||||
order.setCustomer(c0);
|
||||
OrderShipment osh1 = new OrderShipment();
|
||||
order.addShipment(osh1);
|
||||
DB.save(order);
|
||||
|
||||
LoggedSql.start();
|
||||
@@ -194,7 +199,9 @@ public class TestTransparentPersist extends BaseTestCase {
|
||||
Customer c1 = new Customer();
|
||||
c1.setName("newCust CascadePersist");
|
||||
foundOrder.setCustomer(c1);
|
||||
|
||||
foundOrder.getShipments().remove(0);
|
||||
OrderShipment osh2 = new OrderShipment();
|
||||
foundOrder.addShipment(osh2);
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
@@ -204,13 +211,19 @@ public class TestTransparentPersist extends BaseTestCase {
|
||||
|
||||
assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW);
|
||||
assertThat(checkOrder.getCustomer().getName()).isEqualTo("newCust CascadePersist");
|
||||
assertThat(checkOrder.getShipments().size()).isEqualTo(1);
|
||||
|
||||
assertThat(sql).hasSize(5);
|
||||
assertThat(sql).hasSize(10);
|
||||
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date");
|
||||
assertThat(sql.get(1)).contains("insert into o_customer");
|
||||
assertThat(sql.get(2)).contains(" -- bind(");
|
||||
assertThat(sql.get(3)).contains("update o_order set updtime=?, kcustomer_id=? where id=? and updtime=?");
|
||||
assertThat(sql.get(4)).contains(" -- bind(");
|
||||
assertThat(sql.get(5)).contains("select t0.order_id, t0.id, t0.ship_time, t0.cretime, t0.updtime, t0.version, t0.order_id from or_order_ship");
|
||||
assertThat(sql.get(6)).contains("delete from or_order_ship");
|
||||
assertThat(sql.get(7)).contains(" -- bind(");
|
||||
assertThat(sql.get(8)).contains("insert into or_order_ship");
|
||||
assertThat(sql.get(9)).contains(" -- bind(");
|
||||
|
||||
DB.delete(checkOrder);
|
||||
DB.delete(Customer.class, checkOrder.getCustomer().getId());
|
||||
@@ -292,7 +305,8 @@ public class TestTransparentPersist extends BaseTestCase {
|
||||
}
|
||||
|
||||
private List<Object> getDirtyBeansFromPersistenceContext(Transaction transaction) {
|
||||
return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans();
|
||||
final SpiBeanTypeManager mgr = Mockito.mock(SpiBeanTypeManager.class);
|
||||
return ((SpiTransaction)transaction).getPersistenceContext().dirtyBeans(mgr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user