Merge remote-tracking branch 'ebean/master' into pr/bugfix/connection_closed_on_clob

This commit is contained in:
Jonas Pöhler
2021-07-16 13:32:24 +02:00
195 changed files with 3920 additions and 1311 deletions
@@ -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;
@@ -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");
}
@@ -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 {
@@ -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);
@@ -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;
}
}
@@ -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);
}
}