mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64405ade52 | ||
|
|
ce5f1b25f5 | ||
|
|
ae4f50e7b3 | ||
|
|
c9120be347 | ||
|
|
b189e67b4c | ||
|
|
5d5c275c79 | ||
|
|
52f31a7a8e | ||
|
|
6697aecd48 | ||
|
|
348c075a14 | ||
|
|
bf2420702c | ||
|
|
16832ac67a | ||
|
|
47bd2ff03d | ||
|
|
850f1c1469 | ||
|
|
622a90c7d5 | ||
|
|
4c317f11ae | ||
|
|
01bce5cfa6 | ||
|
|
2158925d3c | ||
|
|
2aff6403a2 | ||
|
|
3c4d600187 | ||
|
|
f60ccb9b90 | ||
|
|
2a6108087c | ||
|
|
0da86a82ae | ||
|
|
643b0499c4 | ||
|
|
676bac390e | ||
|
|
79740accfa | ||
|
|
77c6f1cb9f | ||
|
|
538361d5fd | ||
|
|
b17593ba3c | ||
|
|
eb00690b30 | ||
|
|
a772e65d32 | ||
|
|
66f7f69ec7 | ||
|
|
ad52711fe1 | ||
|
|
d6fdb4ee34 | ||
|
|
74c7268d2f | ||
|
|
42fc419759 | ||
|
|
4fb3b9cddc | ||
|
|
c60077174e | ||
|
|
5e893dd2ad |
+1
-1
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
+1
-9
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
+2
-9
@@ -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
|
||||
|
||||
+8
-2
@@ -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;
|
||||
}
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
+5
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+35
-1
@@ -288,7 +288,7 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_removeJoinToMany_when_filterMany() {
|
||||
public void test_filterMany_included() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetch("details")
|
||||
@@ -301,6 +301,40 @@ public class DefaultServer_createOrmQueryRequestTest extends BaseTestCase {
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("details", "details.product", "customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterMany_excludedByOrdering() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetch("customer")
|
||||
.fetch("customer.contacts")
|
||||
.fetch("details")
|
||||
.fetch("details.product")
|
||||
.filterMany("details").eq("orderQuantity", 10)
|
||||
.query();
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterMany_excludedExplicitly() {
|
||||
|
||||
Query<Order> query = Ebean.find(Order.class)
|
||||
.fetchQuery("details")
|
||||
.fetch("details.product")
|
||||
.fetch("customer")
|
||||
.fetch("customer.contacts")
|
||||
.filterMany("details").eq("orderQuantity", 10)
|
||||
.query();
|
||||
|
||||
OrmQueryRequest<Order> queryRequest = queryRequest(query);
|
||||
OrmQueryDetail detail = queryRequest.getQuery().getDetail();
|
||||
|
||||
assertThat(detail.getFetchPaths()).containsExactly("customer", "customer.contacts");
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.tests.model.onetoone.calcd;
|
||||
|
||||
import io.ebean.DB;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestOneToOnePrimaryKeyJoinMapping {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
CalcDInput inputs = new CalcDInput("input0");
|
||||
|
||||
CalcDData data = new CalcDData("data0");
|
||||
inputs.setData(data);
|
||||
inputs.save();
|
||||
|
||||
CalcDInput found = DB.find(CalcDInput.class, inputs.getId());
|
||||
|
||||
assertThat(found).isNotNull();
|
||||
assertThat(found.getName()).isEqualTo("input0");
|
||||
assertThat(found.getData().getName()).isEqualTo("data0");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelX {
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@OneToOne
|
||||
private ESoftDelY y;
|
||||
|
||||
@ManyToOne
|
||||
private ESoftDelZ organization;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ESoftDelY getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(ESoftDelY y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public ESoftDelZ getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(ESoftDelZ organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelY {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private ESoftDelZ organization;
|
||||
|
||||
@OneToOne(mappedBy = "y")
|
||||
private ESoftDelX x;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ESoftDelZ getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(ESoftDelZ organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public ESoftDelX getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(ESoftDelX x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.tests.model.softdelete;
|
||||
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
public class ESoftDelZ {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
}
|
||||
@@ -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,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>
|
||||
|
||||
+1
-1
@@ -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
-8
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>-->
|
||||
<!--<!– <annotationProcessorPaths>–>-->
|
||||
<!--<!– <annotationProcessorPath>–>-->
|
||||
<!--<!– <groupId>io.ebean</groupId>–>-->
|
||||
<!--<!– <artifactId>kotlin-querybean-generator</artifactId>–>-->
|
||||
<!--<!–<!– <version>12.7.1</version>–>–>-->
|
||||
<!--<!– <version>12.8.0-SNAPSHOT</version>–>-->
|
||||
<!--<!– </annotationProcessorPath>–>-->
|
||||
<!--<!– </annotationProcessorPaths>–>-->
|
||||
<!-- </configuration>-->
|
||||
<!-- </execution>-->
|
||||
<!-- </executions>-->
|
||||
<!-- <configuration>-->
|
||||
<!-- <jvmTarget>1.8</jvmTarget>-->
|
||||
<!--<!– <args></args>–>-->
|
||||
<!-- </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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user