Compare commits

...
Author SHA1 Message Date
rbygrave 64405ade52 [maven-release-plugin] prepare release ebean-parent-12.9.1 2021-06-04 17:59:11 +12:00
rbygrave ce5f1b25f5 Bump ebean-maven-plugin to 12.9.1 2021-06-04 17:50:46 +12:00
rbygrave ae4f50e7b3 #2236 - Auto-tune does not work / throws RuntimeException (Regression from 12.7.1)
Note we are missing a test on ProfileManager but doing this for now.
2021-06-04 17:46:31 +12:00
rbygrave c9120be347 No effective change - tidy only H2HistoryTrigger and H2HistoryDdl 2021-06-04 17:37:37 +12:00
rbygrave b189e67b4c #2241 - Offline DDL migration generation for H2 requires H2 Driver 2021-06-04 17:35:19 +12:00
Rob BygraveandGitHub 5d5c275c79 Merge pull request #2240 from FOCONIS/bugfix/ddl-generator-version
Set ddl-generator version to a public-available version + fix classpath for Java8
2021-06-04 17:24:31 +12:00
rbygrave 52f31a7a8e Merge branch 'bkempe-testSelectOneToOneDisjunction' 2021-06-04 17:17:21 +12:00
rbygrave 6697aecd48 #2238 - Select with disjunction of expressions over OneToOne relationship missing join clause
Noting that there might be a better fix. The addJoin() at line 151 is suppressed as it is a duplicate for this case of a !oneToOneExported so a better fix might be to only add the soft delete clause when the join as actually added (not suppressed as a duplicate).
2021-06-04 17:16:50 +12:00
Jonas Pöhler 348c075a14 FIX: Build for java8 2021-06-01 17:56:47 +02:00
Jonas Pöhler bf2420702c FIX: set ddl-generator version to a repo-available version 2021-06-01 17:19:38 +02:00
Ben Kempe 16832ac67a add test testSelectOneToOneDisjunction 2021-05-24 23:47:55 +02:00
rbygrave 47bd2ff03d [maven-release-plugin] prepare for next development iteration 2021-05-23 23:08:47 +12:00
rbygrave 850f1c1469 [maven-release-plugin] prepare release ebean-parent-12.9.0 2021-05-23 23:08:38 +12:00
rbygrave 622a90c7d5 No effective change - tidy whitespace in TransactionManager 2021-05-23 23:00:34 +12:00
rbygrave 4c317f11ae Add additional test for PrimaryKeyJoinColumn 2021-05-23 22:21:05 +12:00
rbygrave 01bce5cfa6 #2226 - Automatically determining join columns and ignoring PrimaryKeyJoinColumn.name Id warning when I want to use Id as a foreign key
Improve the message and dropping to INFO level.
2021-05-23 22:20:40 +12:00
rbygrave 2158925d3c #2202 - kotlin-maven-plugin issue with JDK 16
InaccessibleObjectException: Unable to make protected void java.util.ResourceBundle.setParent(java.util.ResourceBundle) accessible: module java.base does not "opens java.util" to unnamed module @62732be7
2021-05-23 21:28:11 +12:00
Rob BygraveandGitHub 2aff6403a2 Merge pull request #2235 from ebean-orm/feature/2223
#2223 #2224 Support BeanMap modification via entrySet() and keySet()
2021-05-23 17:20:55 +12:00
rbygrave 3c4d600187 #2223 #2224 Support BeanMap modification via entrySet() and keySet() 2021-05-23 17:17:34 +12:00
Rob BygraveandGitHub f60ccb9b90 Merge pull request #2222 from ebean-orm/feature/support-filterMany-inline
Change such that filterMany can be included in the main query.
2021-05-21 17:20:17 +12:00
rbygrave 2a6108087c Bump version to 12.9.0-SNAPSHOT 2021-05-21 17:18:30 +12:00
rbygrave 0da86a82ae #2233 Bump to ebean-agent 12.9.0 2021-05-21 17:14:49 +12:00
rbygrave 643b0499c4 #2233 Add ebean-version.mf so ebean-agent can sniff the internal version
This allows the ebean-agent to support the older behaviour. Devs using the latest IntelliJ ebean plugin will get the old behaviour unless they bump ebean-core to 12.9 or later.
2021-05-21 16:09:15 +12:00
rbygrave 676bac390e #2233 Followup change that unsets load buffer from BeanCollection
- Clears the buffer after it has been used to load BeanCollection's
- Sets the BeanCollection to use the server rather than the Load Buffer just in case there are subsequent calls for loading (which there should not be)
2021-05-21 09:01:45 +12:00
rbygrave 79740accfa #2233 Fix with setter on ToMany now not invoking lazy loading
- ebean-agent changed to not invoke preGetter on ToMany (just like Id)
- EntityBeanIntercept preSetterMany() changed to ensure loading flag set
2021-05-21 08:48:42 +12:00
rbygrave 77c6f1cb9f #2233 Tidy failing test Ebean -> DB and rename test 2021-05-21 08:44:04 +12:00
rbygrave 538361d5fd #2233 Failing test 2021-05-21 08:33:31 +12:00
rbygrave b17593ba3c No effective change - tidy BeanList, BeanMap, BeanSet internals 2021-05-20 21:44:07 +12:00
rbygrave eb00690b30 #2231 - Change OrderBy to not be final to support mocking via Mockito 2021-05-20 14:09:22 +12:00
Rob BygraveandGitHub a772e65d32 Merge pull request #2225 from ebean-orm/dependabot/maven/ebean-core/commons-io-commons-io-2.7
Bump commons-io from 2.5 to 2.7 in /ebean-core
2021-05-20 13:56:00 +12:00
Brian Payne 66f7f69ec7 Fixed bug with soft-delete on one-to-one exported 2021-05-12 09:24:33 -07:00
Brian Payne ad52711fe1 Add test demonstrating soft-delete bug with optional relationship 2021-05-11 10:42:04 -07:00
dependabot[bot]andGitHub d6fdb4ee34 Bump commons-io from 2.5 to 2.7 in /ebean-core
Bumps commons-io from 2.5 to 2.7.

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-26 20:37:55 +00:00
rbygrave 74c7268d2f Change such that filterMany can be included in the main query.
That is, currently a filterMany automatically marks that path as a fetchQuery path. This change turns that off and the filterMany path and predicates can then be included in the main query.

This is better for performance (to include the filterMany path in with the main query) when the query is a findEach and looking to return a large number of results.
2021-04-21 18:57:03 +12:00
rbygrave 42fc419759 #2221 - ebean-redis: bump jedis dependency to 3.6.0 2021-04-20 22:23:33 +12:00
rbygrave 4fb3b9cddc Tidy use of StringHelper replace() in BeanProperty, BaseTableDdl 2021-04-20 22:13:45 +12:00
Robin Bygrave c60077174e Tidy use of StringHelper replace() in BeanProperty, BaseTableDdl 2021-04-20 15:14:20 +12:00
rbygrave 5e893dd2ad [maven-release-plugin] prepare for next development iteration 2021-04-19 21:40:16 +12:00
72 changed files with 1442 additions and 351 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean api</name>
+4 -11
View File
@@ -16,7 +16,7 @@ import java.util.Objects;
* on the Query object.
* </p>
*/
public final class OrderBy<T> implements Serializable {
public class OrderBy<T> implements Serializable {
private static final long serialVersionUID = 9157089257745730539L;
@@ -69,7 +69,6 @@ public final class OrderBy<T> implements Serializable {
* Add a property with ascending order to this OrderBy.
*/
public Query<T> asc(String propertyName) {
list.add(new Property(propertyName, true));
return query;
}
@@ -98,7 +97,6 @@ public final class OrderBy<T> implements Serializable {
return query;
}
/**
* Return true if the property is known to be contained in the order by clause.
*/
@@ -207,7 +205,6 @@ public final class OrderBy<T> implements Serializable {
if (!(obj instanceof OrderBy<?>)) {
return false;
}
OrderBy<?> e = (OrderBy<?>) obj;
return e.list.equals(list);
}
@@ -249,7 +246,7 @@ public final class OrderBy<T> implements Serializable {
/**
* A property and its ascending descending order.
*/
public static final class Property implements Serializable {
public static class Property implements Serializable {
private static final long serialVersionUID = 1546009780322478077L;
@@ -415,13 +412,10 @@ public final class OrderBy<T> implements Serializable {
}
private void parse(String orderByClause) {
if (orderByClause == null) {
return;
}
String[] chunks = orderByClause.split(",");
for (String chunk : chunks) {
for (String chunk : orderByClause.split(",")) {
Property p = parseProperty(chunk);
if (p != null) {
list.add(p);
@@ -467,8 +461,7 @@ public final class OrderBy<T> implements Serializable {
if (s.startsWith("desc")) {
return false;
}
String m = "Expecting [" + s + "] to be asc or desc?";
throw new RuntimeException(m);
throw new RuntimeException("Expecting [" + s + "] to be asc or desc?");
}
private boolean isEmptyString(String s) {
@@ -85,6 +85,8 @@ public final class EntityBeanIntercept implements Serializable {
*/
private static final byte FLAG_CHANGED_PROP = 2;
private static final byte FLAG_CHANGEDLOADED_PROP = 3;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
@@ -569,6 +571,10 @@ public final class EntityBeanIntercept implements Serializable {
flags[propertyIndex] |= FLAG_CHANGED_PROP;
}
private void setChangeLoaded(int propertyIndex) {
flags[propertyIndex] |= FLAG_CHANGEDLOADED_PROP;
}
/**
* Set that an embedded bean has had one of its properties changed.
*/
@@ -937,7 +943,7 @@ public final class EntityBeanIntercept implements Serializable {
if (readOnly) {
throw new IllegalStateException("This bean is readOnly");
}
setChangedProperty(propertyIndex);
setChangeLoaded(propertyIndex);
}
}
@@ -198,10 +198,9 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
if (list == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(list.size()).append("] ");
sb.append("list").append(list).append("");
sb.append("list").append(list);
}
return sb.toString();
}
@@ -175,10 +175,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
/**
* Returns the map entrySet.
* <p>
* This is because the key values may need to be set against the details (so
* they don't need to be set twice).
* </p>
*/
@Override
public Collection<?> getActualEntries() {
@@ -194,7 +190,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
if (map == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(map.size()).append("]");
sb.append(" map").append(map);
@@ -243,17 +238,12 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
@Override
@SuppressWarnings({"unchecked"})
public Set<Entry<K, E>> entrySet() {
init();
if (isReadOnly()) {
return Collections.unmodifiableSet(map.entrySet());
}
if (modifyListening) {
Set<Entry<K, E>> s = map.entrySet();
return new ModifySet(this, s);
}
return map.entrySet();
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
}
@Override
@@ -274,8 +264,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
if (isReadOnly()) {
return Collections.unmodifiableSet(map.keySet());
}
// we don't really care about modifications to the ketSet?
return map.keySet();
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
}
@Override
@@ -346,11 +335,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
if (isReadOnly()) {
return Collections.unmodifiableCollection(map.values());
}
if (modifyListening) {
Collection<E> c = map.values();
return new ModifyCollection<>(this, c);
}
return map.values();
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
}
@Override
@@ -176,7 +176,6 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
if (set == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(set.size()).append("]");
sb.append(" set").append(set);
@@ -25,7 +25,7 @@ class ModifyCollection<E> implements Collection<E> {
* The owner is notified of the additions and removals.
* </p>
*/
public ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
ModifyCollection(BeanCollection<E> owner, Collection<E> c) {
this.owner = owner;
this.c = c;
}
@@ -0,0 +1,131 @@
package io.ebean.common;
import java.util.*;
/**
* Handles the Entry Set for BeanMap.
*/
class ModifyEntrySet<K, E> implements Set<Map.Entry<K, E>> {
private final BeanMap<K, E> owner;
private final Set<Map.Entry<K, E>> entrySet;
ModifyEntrySet(BeanMap<K, E> owner, Set<Map.Entry<K, E>> entrySet) {
this.owner = owner;
this.entrySet = entrySet;
}
@Override
public int size() {
return entrySet.size();
}
@Override
public boolean isEmpty() {
return entrySet.isEmpty();
}
@Override
public boolean contains(Object o) {
return entrySet.contains(o);
}
@Override
public Object[] toArray() {
return entrySet.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return entrySet.toArray(a);
}
@Override
public boolean containsAll(Collection<?> entries) {
return entrySet.containsAll(entries);
}
@Override
public void clear() {
owner.clear();
}
@Override
public boolean add(Map.Entry<K, E> entry) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends Map.Entry<K, E>> c) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("rawtypes")
@Override
public boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry entry = (Map.Entry) o;
final E val = owner.get(entry.getKey());
if (Objects.equals(val, entry.getValue())) {
owner.remove(entry.getKey());
return true;
}
}
return false;
}
@Override
public boolean retainAll(Collection<?> entries) {
boolean modified = false;
final Iterator<Map.Entry<K, E>> it = iterator();
while (it.hasNext()) {
if (!entries.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
@Override
public boolean removeAll(Collection<?> entries) {
boolean modified = false;
for (Object entry : entries) {
modified |= remove(entry);
}
return modified;
}
@Override
public Iterator<Map.Entry<K, E>> iterator() {
return new EntrySetIterator(new ArrayList<>(entrySet).iterator());
}
class EntrySetIterator implements Iterator<Map.Entry<K, E>> {
private final Iterator<Map.Entry<K, E>> iterator;
private Map.Entry<K, E> entry;
EntrySetIterator(Iterator<Map.Entry<K, E>> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Map.Entry<K, E> next() {
entry = iterator.next();
return entry;
}
@Override
public void remove() {
owner.remove(entry.getKey());
iterator.remove();
}
}
}
@@ -0,0 +1,126 @@
package io.ebean.common;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* Handle the Key Set for BeanMap.
*/
class ModifyKeySet<E> implements Set<E> {
private final Set<E> keySet;
private final BeanMap<E, ?> owner;
ModifyKeySet(BeanMap<E, ?> owner, Set<E> keySet) {
this.owner = owner;
this.keySet = keySet;
}
@Override
public int size() {
return keySet.size();
}
@Override
public boolean isEmpty() {
return keySet.isEmpty();
}
@Override
public boolean contains(Object o) {
return keySet.contains(o);
}
@Override
public Object[] toArray() {
return keySet.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return keySet.toArray(a);
}
@Override
public boolean add(E key) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection<? extends E> keys) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
return owner.remove(o) != null;
}
@Override
public boolean containsAll(Collection<?> keys) {
return keySet.containsAll(keys);
}
@Override
public void clear() {
owner.clear();
}
@Override
public Iterator<E> iterator() {
return new KeySetIterator<>(new ArrayList<>(keySet).iterator());
}
@Override
public boolean retainAll(Collection<?> keys) {
return keysMatch(keys, false);
}
@Override
public boolean removeAll(Collection<?> keys) {
return keysMatch(keys, true);
}
private boolean keysMatch(Collection<?> keys, boolean containsMatch) {
boolean changed = false;
final Iterator<E> iterator = iterator();
while (iterator.hasNext()) {
final E key = iterator.next();
if (keys.contains(key) == containsMatch) {
iterator.remove();
changed = true;
}
}
return changed;
}
class KeySetIterator<K> implements Iterator<K> {
private final Iterator<K> iterator;
private K key;
KeySetIterator(Iterator<K> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public K next() {
key = iterator.next();
return key;
}
@Override
public void remove() {
owner.remove(key);
iterator.remove();
}
}
}
@@ -1,24 +0,0 @@
package io.ebean.common;
import io.ebean.bean.BeanCollection;
import java.util.Set;
/**
* Wraps a Set for the purposes of notifying removals and additions to the
* BeanCollection owner.
* <p>
* This is required for persisting ManyToMany objects. Additions and removals
* become inserts and deletes to the intersection table.
* </p>
*/
class ModifySet<E> extends ModifyCollection<E> implements Set<E> {
/**
* Create with an Owner that is notified of any additions or deletions.
*/
public ModifySet(BeanCollection<E> owner, Set<E> s) {
super(owner, s);
}
}
@@ -4,11 +4,7 @@ import org.h2.api.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.*;
import java.util.Arrays;
/**
@@ -43,7 +39,6 @@ public class H2HistoryTrigger implements Trigger {
@Override
public void init(Connection conn, String schemaName, String triggerName, String tableName, boolean before, int type) throws SQLException {
// get the columns for the table
ResultSet rs = conn.getMetaData().getColumns(null, schemaName, tableName, null);
@@ -79,7 +74,6 @@ public class H2HistoryTrigger implements Trigger {
@Override
public void fire(Connection connection, Object[] oldRow, Object[] newRow) throws SQLException {
if (oldRow != null) {
// a delete or update event
Timestamp now = new Timestamp(System.currentTimeMillis());
@@ -99,7 +93,6 @@ public class H2HistoryTrigger implements Trigger {
* Insert the data into the history table.
*/
private void insertIntoHistory(Connection connection, Object[] oldRow) throws SQLException {
try (PreparedStatement stmt = connection.prepareStatement(insertHistorySql)) {
for (int i = 0; i < oldRow.length; i++) {
stmt.setObject(i + 1, oldRow[i]);
@@ -110,11 +103,11 @@ public class H2HistoryTrigger implements Trigger {
@Override
public void close() throws SQLException {
// do nothing
}
@Override
public void remove() throws SQLException {
// do nothing
}
}
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.8.3</tag>
<tag>ebean-parent-12.9.1</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
@@ -46,7 +46,6 @@ public class ProfileManager implements ProfilingListener {
@Override
public boolean isProfileRequest(ObjectGraphNode origin, SpiQuery<?> query) {
ProfileOrigin profileOrigin = profileMap.get(origin.getOriginQueryPoint().getKey());
if (profileOrigin == null) {
profileMap.put(origin.getOriginQueryPoint().getKey(), createProfileOrigin(origin, query));
@@ -61,12 +60,11 @@ public class ProfileManager implements ProfilingListener {
* <p>
* For new profiling entries it is useful to compare the profiling against the current
* query detail that is specified in the code (as the query might already be manually optimised).
* </p>
*/
private ProfileOrigin createProfileOrigin(ObjectGraphNode origin, SpiQuery<?> query) {
ProfileOrigin profileOrigin = new ProfileOrigin(origin.getOriginQueryPoint(), queryTuningAddVersion, profilingBase, profilingRate);
// set the current query detail (fetch group) so that we can compare against profiling for new entries
profileOrigin.setOriginalQuery(query.getDetail().toString());
profileOrigin.setOriginalQuery(query.getDetail().asString());
return profileOrigin;
}
@@ -77,7 +75,6 @@ public class ProfileManager implements ProfilingListener {
*/
@Override
public void collectQueryInfo(ObjectGraphNode node, long beans, long micros) {
if (node != null) {
ObjectGraphOrigin origin = node.getOriginQueryPoint();
if (origin != null) {
@@ -92,11 +89,9 @@ public class ProfileManager implements ProfilingListener {
* <p>
* This is sent to use from a EntityBeanIntercept when the finalise method
* is called on the bean.
* </p>
*/
@Override
public void collectNodeUsage(NodeUsageCollector usageCollector) {
ProfileOrigin profileOrigin = getProfileOrigin(usageCollector.getNode().getOriginQueryPoint());
profileOrigin.collectUsageInfo(usageCollector);
}
@@ -114,16 +109,13 @@ public class ProfileManager implements ProfilingListener {
* Collect all the profiling information.
*/
public AutoTuneCollection profilingCollection(boolean reset) {
AutoTuneCollection req = new AutoTuneCollection();
for (ProfileOrigin origin : profileMap.values()) {
BeanDescriptor<?> desc = server.getBeanDescriptorById(origin.getOrigin().getBeanType());
if (desc != null) {
origin.profilingCollection(desc, req, reset);
}
}
return req;
}
@@ -27,7 +27,7 @@ public class ProfileOriginTest extends BaseTestCase {
OrmQueryDetail detail = po.buildDetail(desc);
assertThat(detail.asStringDebug().trim()).isEqualTo("fetch customer (name)");
assertThat(detail.asString().trim()).isEqualTo("fetch customer (name)");
}
@Test
@@ -46,7 +46,7 @@ public class ProfileOriginTest extends BaseTestCase {
OrmQueryDetail detail = po.buildDetail(desc);
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (name)");
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (name)");
}
@Test
@@ -64,7 +64,7 @@ public class ProfileOriginTest extends BaseTestCase {
OrmQueryDetail detail = po.buildDetail(desc);
assertThat(detail.asStringDebug().trim()).isEqualTo("select (orderDate,customer)");
assertThat(detail.asString().trim()).isEqualTo("select (orderDate,customer)");
}
@Test
@@ -87,7 +87,7 @@ public class ProfileOriginTest extends BaseTestCase {
OrmQueryDetail detail = po.buildDetail(desc);
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
}
@@ -116,7 +116,7 @@ public class ProfileOriginTest extends BaseTestCase {
po.collectUsageInfo(c);
OrmQueryDetail detail = po.buildDetail(desc);
assertThat(detail.asStringDebug()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
assertThat(detail.asString()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
}
private NodeUsageCollector node(String path) {
+17 -17
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean bom</name>
@@ -18,8 +18,8 @@
<ebean-migration.version>12.4.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.8.2</ebean-agent.version>
<ebean-maven-plugin.version>12.8.2</ebean-maven-plugin.version>
<ebean-agent.version>12.9.0</ebean-agent.version>
<ebean-maven-plugin.version>12.9.1</ebean-maven-plugin.version>
</properties>
<dependencyManagement>
@@ -81,88 +81,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
+17 -17
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.8.3</tag>
<tag>ebean-parent-12.9.1</tag>
</scm>
<profiles>
@@ -72,7 +72,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.4a</version>
<version>12.9.0</version>
<scope>test</scope>
</dependency>
@@ -87,19 +87,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
@@ -119,6 +119,15 @@
<scope>provided</scope>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
and not require a separate module for it -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
@@ -214,15 +223,6 @@
<scope>test</scope>
</dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
and not require a separate module for it -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
@@ -282,7 +282,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<version>2.7</version>
<scope>test</scope>
</dependency>
@@ -302,7 +302,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.8.2</version>
<version>12.9.1</version>
<executions>
<execution>
<id>test</id>
@@ -71,7 +71,6 @@ public class LoadManyRequest extends LoadRequest {
* This for use when lazy loading is invoked on methods such as clear() and removeAll() where it
* generally makes sense to only fetch the Id values as the other property information is not
* used.
* </p>
*/
private boolean isOnlyIds() {
return onlyIds;
@@ -91,18 +90,16 @@ public class LoadManyRequest extends LoadRequest {
return loadContext.getBatchSize();
}
private List<Object> getParentIdList() {
private List<Object> parentIdList(SpiEbeanServer server) {
List<Object> idList = new ArrayList<>();
BeanPropertyAssocMany<?> many = getMany();
for (BeanCollection<?> bc : batch) {
idList.add(many.getParentId(bc.getOwnerBean()));
bc.setLoader(server); // don't use the load buffer again
}
if (many.getTargetDescriptor().isPadInExpression()) {
BindPadding.padIds(idList);
}
return idList;
}
@@ -111,9 +108,7 @@ public class LoadManyRequest extends LoadRequest {
}
public SpiQuery<?> createQuery(SpiEbeanServer server) {
BeanPropertyAssocMany<?> many = getMany();
SpiQuery<?> query = many.newQuery(server);
String orderBy = many.getLazyFetchOrderBy();
if (orderBy != null) {
@@ -128,7 +123,7 @@ public class LoadManyRequest extends LoadRequest {
}
query.setLazyLoadForParents(many);
many.addWhereParentIdIn(query, getParentIdList(), loadContext.isUseDocStore());
many.addWhereParentIdIn(query, parentIdList(server), loadContext.isUseDocStore());
query.setPersistenceContext(loadContext.getPersistenceContext());
String mode = isLazy() ? "+lazy" : "+query";
@@ -146,7 +141,6 @@ public class LoadManyRequest extends LoadRequest {
// override to just select the Id values
query.select(many.getTargetIdProperty());
}
return query;
}
@@ -154,10 +148,8 @@ public class LoadManyRequest extends LoadRequest {
* After the query execution check for empty collections and load L2 cache if desired.
*/
public void postLoad() {
BeanDescriptor<?> desc = loadContext.getBeanDescriptor();
BeanPropertyAssocMany<?> many = getMany();
// check for BeanCollection's that where never processed
// in the +query or +lazy load due to no rows (predicates)
for (BeanCollection<?> bc : batch) {
@@ -172,6 +164,5 @@ public class LoadManyRequest extends LoadRequest {
desc.cacheManyPropPut(many, bc, parentId);
}
}
}
}
@@ -105,4 +105,9 @@ public interface SpiExpression extends Expression {
* Check for match to a natural key query returning false if it doesn't match.
*/
boolean naturalKey(NaturalKeyQueryData<?> data);
/**
* Apply property prefix when filterMany expressions included into main query.
*/
void prefixProperty(String path);
}
@@ -43,4 +43,9 @@ public interface SpiExpressionList<T> extends ExpressionList<T>, SpiExpression {
default void applyRowLimits(SpiQuery<?> query) {
// do nothing by default
}
/**
* Apply property prefix when filterMany expressions included in main query.
*/
void prefixProperty(String path);
}
@@ -219,10 +219,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
*/
@Override
public void prepareQuery() {
secondaryQueries = query.convertJoins();
beanDescriptor.prepareQuery(query);
adapterPreQuery();
this.secondaryQueries = query.convertJoins();
this.queryPlanKey = query.prepare(this);
queryPlanKey = query.prepare(this);
}
public boolean isNativeSql() {
@@ -56,8 +56,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.ebean.util.StringHelper.replace;
/**
* Description of a property of a bean. Includes its deployment information such
* as database column mapping information.
@@ -356,13 +354,13 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
}
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
if (descriptor != null) {
s = replace(s, "${ta}.", "${}");
s = replace(s, "${ta}", "${}");
if (s != null && descriptor != null) {
s = s.replace("${ta}.", "${}");
s = s.replace("${ta}", "${}");
if (dbEncrypted) {
s = dbEncryptFunction.getDecryptSql(s);
String namedParam = ":encryptkey_" + descriptor.getBaseTable() + "___" + dbColumn;
s = replace(s, "?", namedParam);
s = s.replace("?", namedParam);
}
}
return InternString.intern(s);
@@ -54,7 +54,6 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
}
private void readAssocOne(DeployBeanPropertyAssocOne<?> prop) {
ManyToOne manyToOne = get(prop, ManyToOne.class);
if (manyToOne != null) {
readManyToOne(manyToOne, prop);
@@ -183,7 +182,6 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
}
private void readManyToOne(ManyToOne propAnn, DeployBeanPropertyAssocOne<?> beanProp) {
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
setTargetType(propAnn.targetEntity(), beanProp);
setBeanTable(beanProp);
@@ -194,7 +192,6 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
}
private void readOneToOne(OneToOne propAnn, DeployBeanPropertyAssocOne<?> prop) {
prop.setOneToOne();
prop.setDbInsertable(true);
prop.setDbUpdateable(true);
@@ -223,21 +220,19 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
}
private void readPrimaryKeyJoin(PrimaryKeyJoinColumn primaryKeyJoin, DeployBeanPropertyAssocOne<?> prop) {
if (!prop.isOneToOne()) {
throw new IllegalStateException("Expecting property " + prop.getFullBeanName() + " with PrimaryKeyJoinColumn to be a OneToOne?");
}
prop.setPrimaryKeyJoin(true);
if (!primaryKeyJoin.name().isEmpty()) {
log.warn("Automatically determining join columns and ignoring PrimaryKeyJoinColumn.name {} on {}", primaryKeyJoin.name(), prop.getFullBeanName());
log.info("Automatically determining join columns for @PrimaryKeyJoinColumn - ignoring PrimaryKeyJoinColumn.name attribute [{}] on {}", primaryKeyJoin.name(), prop.getFullBeanName());
}
if (!primaryKeyJoin.referencedColumnName().isEmpty()) {
log.warn("Automatically determining join columns and Ignoring PrimaryKeyJoinColumn.referencedColumnName {} on {}", primaryKeyJoin.referencedColumnName(), prop.getFullBeanName());
log.info("Automatically determining join columns for @PrimaryKeyJoinColumn - Ignoring PrimaryKeyJoinColumn.referencedColumnName attribute [{}] on {}", primaryKeyJoin.referencedColumnName(), prop.getFullBeanName());
}
BeanTable baseBeanTable = factory.getBeanTable(info.getDescriptor().getBeanType());
String localPrimaryKey = baseBeanTable.getIdColumn();
String foreignColumn = getBeanTable(prop).getIdColumn();
@@ -245,7 +240,6 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
}
private void readEmbedded(DeployBeanPropertyAssocOne<?> prop, Embedded embedded) {
if (descriptor.isDocStoreOnly() && prop.getDocStoreDoc() == null) {
prop.setDocStoreEmbedded("");
}
@@ -257,7 +251,6 @@ public class AnnotationAssocOnes extends AnnotationAssoc {
} catch (NoSuchMethodError e) {
// using standard JPA API without prefix option, maybe in EE container
}
readEmbeddedAttributeOverrides(prop);
}
@@ -16,12 +16,17 @@ import io.ebeaninternal.api.NaturalKeyQueryData;
*/
public abstract class AbstractExpression implements SpiExpression {
protected final String propName;
protected String propName;
protected AbstractExpression(String propName) {
this.propName = propName;
}
@Override
public void prefixProperty(String path) {
this.propName = path + "." + propName;
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// by default can't use naturalKey cache
@@ -17,8 +17,8 @@ class BetweenPropertyExpression extends NonPrepareExpression {
private static final String BETWEEN = " between ";
private final String lowProperty;
private final String highProperty;
private String lowProperty;
private String highProperty;
private final Object value;
BetweenPropertyExpression(String lowProperty, String highProperty, Object value) {
@@ -27,6 +27,12 @@ class BetweenPropertyExpression extends NonPrepareExpression {
this.value = value;
}
@Override
public void prefixProperty(String path) {
this.lowProperty = path + "." + lowProperty;
this.highProperty = path + "." + highProperty;
}
protected String name(String propName) {
return propName;
}
@@ -88,6 +88,13 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
}
}
@Override
public void prefixProperty(String path) {
for (SpiExpression exp : list) {
exp.prefixProperty(path);
}
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -126,6 +126,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
}
@Override
public void prefixProperty(String path) {
for (SpiExpression exp : list) {
exp.prefixProperty(path);
}
}
@Override
public Junction<T> toJunction() {
return new JunctionExpression<>(Junction.Type.FILTER, this);
@@ -36,6 +36,11 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
this.subQuery = null;
}
@Override
public void prefixProperty(String path) {
// do nothing
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -19,6 +19,11 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
this.value = value;
}
@Override
public void prefixProperty(String path) {
throw new IllegalStateException("Not allowed?");
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeId(value);
@@ -66,6 +66,11 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
this.exprList = exprList;
}
@Override
public void prefixProperty(String path) {
exprList.prefixProperty(path);
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -57,6 +57,12 @@ abstract class LogicExpression implements SpiExpression {
this.expTwo = (SpiExpression) expTwo;
}
@Override
public void prefixProperty(String path) {
expOne.prefixProperty(path);
expTwo.prefixProperty(path);
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -24,6 +24,11 @@ class NestedPathWrapperExpression implements SpiExpression {
this.delegate = delegate;
}
@Override
public void prefixProperty(String path) {
// do nothing
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -9,6 +9,11 @@ import io.ebeaninternal.api.NaturalKeyQueryData;
*/
abstract class NonPrepareExpression implements SpiExpression {
@Override
public void prefixProperty(String path) {
// do nothing
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -17,6 +17,11 @@ class NoopExpression implements SpiExpression {
protected static final NoopExpression INSTANCE = new NoopExpression();
@Override
public void prefixProperty(String path) {
// do nothing
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -22,6 +22,11 @@ final class NotExpression implements SpiExpression {
this.exp = (SpiExpression) exp;
}
@Override
public void prefixProperty(String path) {
exp.prefixProperty(path);
}
@Override
public boolean naturalKey(NaturalKeyQueryData<?> data) {
// can't use naturalKey cache
@@ -201,7 +201,6 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
@Override
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
lock.lock();
try {
boolean useCache = !onlyIds && context.hitCache && context.property.isUseCache();
@@ -215,6 +214,7 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
// find it using instance equality - avoiding equals() and potential deadlock issue
if (list.get(i) == bc) {
list.remove(i);
bc.setLoader(context.parent.getEbeanServer());
return;
}
}
@@ -222,10 +222,9 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
}
}
// Should reduce the list by checking each beanCollection in the L2 first before executing the query
LoadManyRequest req = new LoadManyRequest(this, onlyIds, useCache);
context.parent.getEbeanServer().loadMany(req);
context.parent.getEbeanServer().loadMany(new LoadManyRequest(this, onlyIds, useCache));
// clear the buffer as all entries have been loaded
list.clear();
} finally {
lock.unlock();
}
@@ -5,6 +5,7 @@ import io.ebean.bean.EntityBean;
import io.ebean.core.type.ScalarType;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.DbReadContext;
import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
@@ -130,6 +131,14 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
}
}
boolean oneToOneExported = false;
if (assocBeanProperty instanceof BeanPropertyAssocOne) {
BeanPropertyAssocOne<?> oneToOneProp = (BeanPropertyAssocOne<?>) assocBeanProperty;
if (oneToOneProp.isOneToOneExported()) {
oneToOneExported = true;
}
}
if (pathContainsMany) {
// "promote" to left join as the path contains a many
joinType = SqlJoinType.OUTER;
@@ -140,7 +149,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
assocBeanProperty.appendFrom(ctx, joinType);
}
joinType = assocBeanProperty.addJoin(joinType, prefix, ctx);
if (assocBeanProperty.isTargetSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
if (!oneToOneExported && assocBeanProperty.isTargetSoftDelete() && temporalMode != SpiQuery.TemporalMode.SOFT_DELETED) {
ctx.append(" and ").append(assocBeanProperty.getSoftDeletePredicate(ctx.getTableAlias(prefix)));
}
}
@@ -1238,6 +1238,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
* Prepare the expressions (compile sub-queries etc).
*/
private void prepareExpressions(BeanQueryRequest<?> request) {
detail.prepareExpressions(request);
if (whereExpressions != null) {
whereExpressions.prepareExpression(request);
}
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.FetchConfig;
import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
@@ -9,25 +10,16 @@ import io.ebeaninternal.server.el.ElPropertyValue;
import javax.persistence.PersistenceException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Represents the internal structure of an Object Relational query.
* <p>
* Holds the select() and join() details of a ORM query.
* </p>
* <p>
* It is worth noting that for AutoTune a "tuned fetch info" builds an instance of OrmQueryDetail.
* Tuning a query is a matter of replacing an instance of this class with one that has been tuned
* with select() and join() set.
* </p>
*/
public class OrmQueryDetail implements Serializable {
@@ -81,7 +73,6 @@ public class OrmQueryDetail implements Serializable {
* Return true if equal in terms of autoTune (select and fetch without property ordering).
*/
public boolean isAutoTuneEqual(OrmQueryDetail otherDetail) {
if (!isSameByAutoTune(baseProps, otherDetail.baseProps)) {
return false;
}
@@ -109,7 +100,7 @@ public class OrmQueryDetail implements Serializable {
/**
* Return the detail in string form.
*/
public String asStringDebug() {
public String asString() {
StringBuilder sb = new StringBuilder();
if (baseProps.hasProperties()) {
baseProps.asStringDebug("select ", sb);
@@ -175,9 +166,7 @@ public class OrmQueryDetail implements Serializable {
}
private List<OrmQueryProperties> removeSecondaryQueries(boolean lazyQuery) {
ArrayList<String> matchingPaths = new ArrayList<>(2);
for (OrmQueryProperties chunk : fetchPaths.values()) {
boolean match = lazyQuery ? chunk.isLazyFetch() : chunk.isQueryFetch();
if (match) {
@@ -191,7 +180,6 @@ public class OrmQueryDetail implements Serializable {
// sort into depth order to remove
Collections.sort(matchingPaths);
// the list of secondary queries
ArrayList<OrmQueryProperties> props = new ArrayList<>();
@@ -225,14 +213,11 @@ public class OrmQueryDetail implements Serializable {
OrmQueryProperties chunk = getChunk(split[0], true);
chunk.addSecondaryQueryJoin(split[1]);
}
return props;
}
boolean tuneFetchProperties(OrmQueryDetail tunedDetail) {
boolean tuned = false;
OrmQueryProperties tunedRoot = tunedDetail.getChunk(null, false);
if (tunedRoot != null) {
tuned = true;
@@ -257,10 +242,7 @@ public class OrmQueryDetail implements Serializable {
}
/**
* Remove all joins and properties.
* <p>
* Typically for the row count query.
* </p>
* Remove all joins and properties. Typically for the row count query.
*/
public void clear() {
fetchPaths.clear();
@@ -306,7 +288,6 @@ public class OrmQueryDetail implements Serializable {
}
private void sortFetchPaths(BeanDescriptor<?> d, boolean addIds) {
if (!fetchPaths.isEmpty()) {
LinkedHashMap<String, OrmQueryProperties> sorted = new LinkedHashMap<>();
for (OrmQueryProperties p : fetchPaths.values()) {
@@ -317,7 +298,6 @@ public class OrmQueryDetail implements Serializable {
}
private void sortFetchPaths(BeanDescriptor<?> d, OrmQueryProperties p, LinkedHashMap<String, OrmQueryProperties> sorted, boolean addId) {
String path = p.getPath();
if (!sorted.containsKey(path)) {
String parentPath = p.getParentPath();
@@ -339,7 +319,6 @@ public class OrmQueryDetail implements Serializable {
parentProp = new OrmQueryProperties(parentPath, Collections.emptySet());
}
}
sortFetchPaths(d, parentProp, sorted, addId);
sorted.put(path, p);
}
@@ -350,14 +329,12 @@ public class OrmQueryDetail implements Serializable {
* Mark 'fetch joins' to 'many' properties over to 'query joins' where needed.
*/
void markQueryJoins(BeanDescriptor<?> beanDescriptor, String lazyLoadManyPath, boolean allowOne, boolean addIds) {
if (fetchPaths.isEmpty()) {
return;
}
// the name of the many fetch property if there is one
String manyFetchProperty = null;
// flag that is set once the many fetch property is chosen
boolean fetchJoinFirstMany = allowOne;
@@ -375,6 +352,7 @@ public class OrmQueryDetail implements Serializable {
// letting the first one remain a 'fetch join'
fetchJoinFirstMany = false;
manyFetchProperty = pair.getPath();
chunk.filterManyInline();
} else {
// convert this one over to a 'query join'
chunk.markForQueryJoin();
@@ -388,7 +366,6 @@ public class OrmQueryDetail implements Serializable {
* Sort the fetch entries taking into account fetchPreference on the path.
*/
private List<FetchEntry> sortByFetchPreference(BeanDescriptor<?> desc) {
List<FetchEntry> entries = new ArrayList<>(fetchPaths.size());
int idx = 0;
for (Map.Entry<String, OrmQueryProperties> entry : fetchPaths.entrySet()) {
@@ -452,11 +429,9 @@ public class OrmQueryDetail implements Serializable {
* </p>
*/
public void setDefaultSelectClause(BeanDescriptor<?> desc) {
if (desc.hasDefaultSelectClause() && !hasSelectClause()) {
baseProps = new OrmQueryProperties(null, desc.getDefaultSelectClause());
}
for (OrmQueryProperties joinProps : fetchPaths.values()) {
if (!joinProps.hasSelectClause()) {
BeanDescriptor<?> assocDesc = desc.getBeanDescriptor(joinProps.getPath());
@@ -506,7 +481,6 @@ public class OrmQueryDetail implements Serializable {
props = new OrmQueryProperties(path);
fetch(props);
return props;
} else {
return props;
}
@@ -516,9 +490,7 @@ public class OrmQueryDetail implements Serializable {
* Return true if the fetch path is included.
*/
public boolean includesPath(String path) {
OrmQueryProperties chunk = fetchPaths.get(path);
// may not have fetch properties if just +cache etc
return chunk != null && !chunk.isCache();
}
@@ -537,6 +509,15 @@ public class OrmQueryDetail implements Serializable {
return fetchPaths.entrySet();
}
/**
* Prepare filterMany expressions that are being included into the main query.
*/
public void prepareExpressions(BeanQueryRequest<?> request) {
for (OrmQueryProperties value : fetchPaths.values()) {
value.prepareExpressions(request);
}
}
private static class FetchEntry implements Comparable<FetchEntry> {
private final int index;
@@ -4,6 +4,7 @@ import io.ebean.ExpressionFactory;
import io.ebean.FetchConfig;
import io.ebean.OrderBy;
import io.ebean.Query;
import io.ebean.event.BeanQueryRequest;
import io.ebean.util.SplitName;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionFactory;
@@ -178,8 +179,6 @@ public class OrmQueryProperties implements Serializable {
SpiExpressionFactory queryEf = (SpiExpressionFactory) rootQuery.getExpressionFactory();
ExpressionFactory filterEf = queryEf.createExpressionFactory();// exprPath);
filterMany = new FilterExpressionList(exprPath, filterEf, rootQuery);
// by default we need to make this a 'query join' now
markForQueryJoin = true;
}
return filterMany;
}
@@ -194,6 +193,24 @@ public class OrmQueryProperties implements Serializable {
return filterMany.trimPath(trimPath);
}
/**
* Adjust filterMany expressions for inclusion in main query.
*/
public void filterManyInline() {
if (filterMany != null){
filterMany.prefixProperty(path);
}
}
/**
* Prepare filterMany expressions for query plan key.
*/
public void prepareExpressions(BeanQueryRequest<?> request) {
if (filterMany != null) {
filterMany.prepareExpression(request);
}
}
/**
* Return the filterMany expression list (can be null).
*/
@@ -206,7 +223,6 @@ public class OrmQueryProperties implements Serializable {
*/
public void setFilterMany(SpiExpressionList<?> filterMany) {
this.filterMany = filterMany;
this.markForQueryJoin = true;
}
/**
@@ -53,7 +53,6 @@ import java.util.concurrent.atomic.AtomicLong;
* Manages transactions.
* <p>
* Keeps the Cache and Cluster in sync when transactions are committed.
* </p>
*/
public class TransactionManager implements SpiTransactionManager {
@@ -198,8 +197,6 @@ public class TransactionManager implements SpiTransactionManager {
this.txnMain = metricFactory.createTimedMetric("txn.main");
this.txnReadOnly = metricFactory.createTimedMetric("txn.readonly");
this.txnNamed = metricFactory.createTimedMetricMap("txn.named.");
// Add gauges for db pool size
scopeManager.register(this);
}
@@ -304,20 +301,16 @@ public class TransactionManager implements SpiTransactionManager {
* There is a potential optimisation available when read committed is the default
* isolation level. If it is, then Connections used only for queries do not require
* commit or rollback but instead can just be put back into the pool via close().
* </p>
* <p>
* If the Isolation level is higher (say SERIALIZABLE) then Connections used
* just for queries do need to be committed or rollback after the query.
* </p>
*/
OnQueryOnly initOnQueryOnly(OnQueryOnly dbPlatformOnQueryOnly) {
// first check for a system property 'override'
String systemPropertyValue = System.getProperty("ebean.transaction.onqueryonly");
if (systemPropertyValue != null) {
return OnQueryOnly.valueOf(systemPropertyValue.trim().toUpperCase());
}
// default to rollback if not defined on the platform
return dbPlatformOnQueryOnly == null ? OnQueryOnly.COMMIT : dbPlatformOnQueryOnly;
}
@@ -359,9 +352,7 @@ public class TransactionManager implements SpiTransactionManager {
* Wrap an externally supplied Connection with a known transaction id.
*/
private SpiTransaction wrapExternalConnection(String id, Connection c) {
ExternalJdbcTransaction t = new ExternalJdbcTransaction(id, true, c, this);
// set the default batch mode
t.setBatchMode(persistBatch);
t.setBatchOnCascade(persistBatchOnCascade);
@@ -409,7 +400,6 @@ public class TransactionManager implements SpiTransactionManager {
*/
@Override
public void notifyOfRollback(SpiTransaction transaction, Throwable cause) {
try {
if (txnLogger.isDebug()) {
String msg = transaction.getLogPrefix() + "Rollback";
@@ -418,7 +408,6 @@ public class TransactionManager implements SpiTransactionManager {
}
txnLogger.debug(msg);
}
} catch (Exception ex) {
logger.error("Error while notifying TransactionEventListener of rollback event", ex);
}
@@ -445,7 +434,6 @@ public class TransactionManager implements SpiTransactionManager {
}
private void formatThrowable(Throwable e, StringBuilder sb) {
sb.append(e.toString());
StackTraceElement[] stackTrace = e.getStackTrace();
if (stackTrace.length > 0) {
@@ -468,11 +456,9 @@ public class TransactionManager implements SpiTransactionManager {
if (txnLogger.isDebug()) {
txnLogger.debug(transaction.getLogPrefix() + "Commit");
}
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, transaction);
postCommit.notifyLocalCache();
backgroundExecutor.execute(postCommit.backgroundNotify());
} catch (Exception ex) {
logger.error("NotifyOfCommit failed. L2 Cache potentially not notified.", ex);
}
@@ -488,7 +474,6 @@ public class TransactionManager implements SpiTransactionManager {
}
private void externalModificationEvent(TransactionEventTable tableEvents) {
TransactionEvent event = new TransactionEvent();
event.add(tableEvents);
@@ -501,25 +486,21 @@ public class TransactionManager implements SpiTransactionManager {
* Notify local BeanPersistListeners etc of events from another server in the cluster.
*/
public void remoteTransactionEvent(RemoteTransactionEvent remoteEvent) {
if (clusterLogger.isDebugEnabled()) {
clusterLogger.debug("processing {}", remoteEvent);
}
CacheChangeSet changeSet = new CacheChangeSet();
RemoteTableMod tableMod = remoteEvent.getRemoteTableMod();
if (tableMod != null) {
changeSet.addInvalidate(tableMod.getTables());
}
List<TableIUD> tableIUDList = remoteEvent.getTableIUDList();
if (tableIUDList != null) {
for (TableIUD tableIUD : tableIUDList) {
beanDescriptorManager.cacheNotify(tableIUD, changeSet);
}
}
// note DeleteById is written as BeanPersistIds and getBeanPersistList()
// processes both Bean IUD and DeleteById
List<BeanPersistIds> beanPersistList = remoteEvent.getBeanPersistList();
@@ -528,7 +509,6 @@ public class TransactionManager implements SpiTransactionManager {
persistIds.notifyCache(changeSet);
}
}
changeSet.apply();
}
@@ -543,10 +523,8 @@ public class TransactionManager implements SpiTransactionManager {
* Prepare and then send/log the changeSet.
*/
void sendChangeLog(final ChangeSet changeSet) {
// can set userId, userIpAddress & userContext if desired
if (changeLogPrepare.prepare(changeSet)) {
if (changeLogAsync) {
// call the log method in background
backgroundExecutor.execute(() -> changeLogListener.log(changeSet));
@@ -653,9 +631,7 @@ public class TransactionManager implements SpiTransactionManager {
* Begin a scoped transaction.
*/
public ScopedTransaction beginScopedTransaction(TxScope txScope) {
txScope = initTxScope(txScope);
ScopedTransaction txnContainer = getActiveScoped();
boolean setToScope;
@@ -678,7 +654,6 @@ public class TransactionManager implements SpiTransactionManager {
if (nestedSavepoint && (type == TxType.REQUIRED || type == TxType.REQUIRES_NEW)) {
createTransaction = true;
transaction = createSavepoint(transaction, this);
} else {
createTransaction = isCreateNewTransaction(transaction, type);
if (createTransaction) {
@@ -748,32 +723,26 @@ public class TransactionManager implements SpiTransactionManager {
* Determine whether to create a new transaction or not.
* <p>
* This will also potentially throw exceptions for MANDATORY and NEVER types.
* </p>
*/
private boolean isCreateNewTransaction(SpiTransaction current, TxType type) {
switch (type) {
case REQUIRED:
case SUPPORTS:
return current == null;
case REQUIRES_NEW:
return true;
case MANDATORY:
if (current == null) {
throw new PersistenceException("Transaction missing when MANDATORY");
}
return false;
case NEVER:
if (current != null) {
throw new PersistenceException("Transaction exists for Transactional NEVER");
}
return true; // always use NoTransaction instance
case NOT_SUPPORTED:
return true; // always use NoTransaction instance
default:
throw new RuntimeException("Should never get here?");
}
@@ -0,0 +1 @@
ebean-version: 129
@@ -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;
}
}
@@ -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");
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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 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%)");
}
}
@@ -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)
@@ -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");
}
}
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
@@ -76,7 +76,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.8.2</version>
<version>12.9.1</version>
<executions>
<execution>
<id>test</id>
@@ -150,7 +150,7 @@ public class BaseTableDdl implements TableDdl {
buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine();
}
for (String ddlScript : before) {
buffer.appendStatement(translate(ddlScript, tableName, columnName, this.defaultValue));
buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue));
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.dbmigration.ddlgeneration.platform;
import io.ebean.config.dbplatform.h2.H2HistoryTrigger;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
import io.ebeaninternal.dbmigration.model.MTable;
@@ -12,7 +11,7 @@ import java.io.IOException;
*/
public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
private static final String TRIGGER_CLASS = H2HistoryTrigger.class.getName();
private static final String TRIGGER_CLASS = "io.ebean.config.dbplatform.h2.H2HistoryTrigger";
H2HistoryDdl() {
this.sysPeriodType = "timestamp";
@@ -22,31 +21,25 @@ public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
@Override
protected void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException {
buffer.append("drop trigger ").append(updateTriggerName(baseTable)).endOfStatement();
}
@Override
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
String baseTableName = table.getName();
DdlBuffer apply = writer.applyHistoryTrigger();
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName);
}
@Override
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
recreateHistoryView(update);
DdlBuffer buffer = update.historyTriggerBuffer();
dropTriggers(buffer, update.getBaseTable());
addCreateTrigger(buffer, updateTriggerName(update.getBaseTable()), update.getBaseTable());
}
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable) throws IOException {
// Note that this does not take into account the historyTable name (excepts _history suffix) and
// does not take into account excluded columns (all columns included in history)
apply
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean external mapping api</name>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.8.3</tag>
<tag>ebean-parent-12.9.1</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean postgis</name>
@@ -23,7 +23,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
@@ -74,7 +74,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
@@ -57,21 +57,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
+7 -7
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -16,41 +16,41 @@
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean test</name>
@@ -29,14 +29,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>ebean composite</name>
@@ -22,20 +22,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
</dependency>
</dependencies>
+42 -43
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>kotlin querybean generator</name>
@@ -12,7 +12,7 @@
<artifactId>kotlin-querybean-generator</artifactId>
<properties>
<kotlin.version>1.4.31</kotlin.version>
<kotlin.version>1.5.0</kotlin.version>
</properties>
<dependencies>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
@@ -43,7 +43,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
@@ -64,7 +64,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<scope>test</scope>
</dependency>
@@ -81,43 +81,42 @@
<build>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<!-- <plugin>-->
<!-- <groupId>org.jetbrains.kotlin</groupId>-->
<!-- <artifactId>kotlin-maven-plugin</artifactId>-->
<!-- <version>${kotlin.version}</version>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <id>test-compile</id>-->
<!-- <phase>test-compile</phase>-->
<!-- <goals>-->
<!-- <goal>test-compile</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- <execution>-->
<!-- <id>test-kapt</id>-->
<!-- <goals>-->
<!-- <goal>test-kapt</goal>-->
<!-- </goals>-->
<!-- <configuration>-->
<!-- <sourceDirs>-->
<!-- <sourceDir>src/test/kotlin</sourceDir>-->
<!-- </sourceDirs>-->
<!--&lt;!&ndash; <annotationProcessorPaths>&ndash;&gt;-->
<!--&lt;!&ndash; <annotationProcessorPath>&ndash;&gt;-->
<!--&lt;!&ndash; <groupId>io.ebean</groupId>&ndash;&gt;-->
<!--&lt;!&ndash; <artifactId>kotlin-querybean-generator</artifactId>&ndash;&gt;-->
<!--&lt;!&ndash;&lt;!&ndash; <version>12.7.1</version>&ndash;&gt;&ndash;&gt;-->
<!--&lt;!&ndash; <version>12.8.0-SNAPSHOT</version>&ndash;&gt;-->
<!--&lt;!&ndash; </annotationProcessorPath>&ndash;&gt;-->
<!--&lt;!&ndash; </annotationProcessorPaths>&ndash;&gt;-->
<!-- </configuration>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- <configuration>-->
<!-- <jvmTarget>1.8</jvmTarget>-->
<!--&lt;!&ndash; <args></args>&ndash;&gt;-->
<!-- </configuration>-->
<!-- </plugin>-->
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
<execution>
<id>test-kapt</id>
<goals>
<goal>test-kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/test/kotlin</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.8.2</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
</executions>
<configuration>
<jvmTarget>1.8</jvmTarget>
<!-- <args></args>-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
@@ -146,7 +145,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>12.8.2</version>
<version>12.9.1</version>
<executions>
<execution>
<id>test</id>
+2 -2
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>12.8.3</version>
<version>12.9.1</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -18,7 +18,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.8.3</tag>
<tag>ebean-parent-12.9.1</tag>
</scm>
<licenses>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.8.3</version>
<version>12.9.1</version>
</parent>
<name>querybean generator</name>