mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a61614430 | ||
|
|
9734ae5787 | ||
|
|
b817d5ee4d | ||
|
|
0036473971 | ||
|
|
a020bb15a1 | ||
|
|
efa86043bf | ||
|
|
eb1ea5ddd2 | ||
|
|
a83a4fa1c4 | ||
|
|
fe71c7cc4e | ||
|
|
5522d56e8d | ||
|
|
7e995efb62 | ||
|
|
ef46bc86cc | ||
|
|
0e75c50be5 | ||
|
|
cd1cdb027f | ||
|
|
66703a3a29 | ||
|
|
56e65d7463 | ||
|
|
eb7277aa13 | ||
|
|
42f9e74d91 | ||
|
|
be24e11b91 | ||
|
|
42d3e9eb91 | ||
|
|
bb164a0763 | ||
|
|
3a50c264b1 | ||
|
|
0e7dc4209c | ||
|
|
72845acbad | ||
|
|
29d88d7de8 | ||
|
|
c81d329100 | ||
|
|
7c1c144af5 | ||
|
|
7809858634 | ||
|
|
bd3cb3c547 | ||
|
|
db25cb7bfb | ||
|
|
55a9ba7170 | ||
|
|
2df2224286 | ||
|
|
e1e8092144 |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>11.22.2</version>
|
||||
<version>11.22.6</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-11.22.2</tag>
|
||||
<tag>ebean-11.22.6</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.util.StringHelper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an Order By for a Query.
|
||||
@@ -74,6 +77,15 @@ public final class OrderBy<T> implements Serializable {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with ascending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> asc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, true, collation));
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
@@ -83,6 +95,16 @@ public final class OrderBy<T> implements Serializable {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property with descending order to this OrderBy.
|
||||
*/
|
||||
public Query<T> desc(String propertyName, String collation) {
|
||||
|
||||
list.add(new Property(propertyName, false, collation));
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the property is known to be contained in the order by clause.
|
||||
*/
|
||||
@@ -231,6 +253,8 @@ public final class OrderBy<T> implements Serializable {
|
||||
|
||||
private boolean ascending;
|
||||
|
||||
private String collation;
|
||||
|
||||
private String nulls;
|
||||
|
||||
private String highLow;
|
||||
@@ -247,17 +271,32 @@ public final class OrderBy<T> implements Serializable {
|
||||
this.highLow = highLow;
|
||||
}
|
||||
|
||||
public Property(String property, boolean ascending, String collation) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
this.collation = collation;
|
||||
}
|
||||
|
||||
public Property(String property, boolean ascending, String collation, String nulls, String highLow) {
|
||||
this.property = property;
|
||||
this.ascending = ascending;
|
||||
this.collation = collation;
|
||||
this.nulls = nulls;
|
||||
this.highLow = highLow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this Property with the path trimmed.
|
||||
*/
|
||||
public Property copyWithTrim(String path) {
|
||||
return new Property(property.substring(path.length() + 1), ascending, nulls, highLow);
|
||||
return new Property(property.substring(path.length() + 1), ascending, collation, nulls, highLow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = property.hashCode();
|
||||
hc = hc * 92821 + (ascending ? 0 : 1);
|
||||
hc = hc * 92821 + (collation == null ? 0 : collation.hashCode());
|
||||
hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode());
|
||||
hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode());
|
||||
return hc;
|
||||
@@ -274,8 +313,9 @@ public final class OrderBy<T> implements Serializable {
|
||||
Property e = (Property) obj;
|
||||
if (ascending != e.ascending) return false;
|
||||
if (!property.equals(e.property)) return false;
|
||||
if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false;
|
||||
return highLow != null ? highLow.equals(e.highLow) : e.highLow == null;
|
||||
if (!Objects.equals(collation, e.collation)) return false;
|
||||
if (!Objects.equals(nulls, e.nulls)) return false;
|
||||
return Objects.equals(highLow, e.highLow);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,7 +324,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
|
||||
public String toStringFormat() {
|
||||
if (nulls == null) {
|
||||
if (nulls == null && collation == null) {
|
||||
if (ascending) {
|
||||
return property;
|
||||
} else {
|
||||
@@ -292,11 +332,23 @@ public final class OrderBy<T> implements Serializable {
|
||||
}
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(property);
|
||||
if (collation != null) {
|
||||
if (collation.contains("${}")) {
|
||||
// this is a complex collation, e.g. DB2 - we must replace the property
|
||||
sb.append(StringHelper.replaceString(collation, "${}", property));
|
||||
} else {
|
||||
sb.append(property);
|
||||
sb.append(" collate ").append(collation);
|
||||
}
|
||||
} else {
|
||||
sb.append(property);
|
||||
}
|
||||
if (!ascending) {
|
||||
sb.append(" ").append("desc");
|
||||
}
|
||||
sb.append(" ").append(nulls).append(" ").append(highLow);
|
||||
if (nulls != null) {
|
||||
sb.append(" ").append(nulls).append(" ").append(highLow);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -319,7 +371,7 @@ public final class OrderBy<T> implements Serializable {
|
||||
* Return a copy of this property.
|
||||
*/
|
||||
public Property copy() {
|
||||
return new Property(property, ascending, nulls, highLow);
|
||||
return new Property(property, ascending, collation, nulls, highLow);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,21 +71,30 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
/**
|
||||
* Used when a bean is partially filled.
|
||||
*/
|
||||
private final boolean[] loadedProps;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
private static final byte FLAG_LOADED_PROP = 1;
|
||||
|
||||
/**
|
||||
* Set of changed properties.
|
||||
*/
|
||||
private boolean[] changedProps;
|
||||
private static final byte FLAG_CHANGED_PROP = 2;
|
||||
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distingush
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private boolean[] embeddedDirty;
|
||||
private static final byte FLAG_EMBEDDED_DIRTY = 4;
|
||||
|
||||
/**
|
||||
* Flags indicating if a property is a dirty embedded bean. Used to distingush
|
||||
* between an embedded bean being completely overwritten and one of its
|
||||
* embedded properties being made dirty.
|
||||
*/
|
||||
private static final byte FLAG_ORIG_VALUE_SET = 8;
|
||||
|
||||
private final byte[] flags;
|
||||
|
||||
private boolean fullyLoadedBean;
|
||||
|
||||
private Object[] origValues;
|
||||
|
||||
@@ -102,7 +111,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
*/
|
||||
public EntityBeanIntercept(Object ownerBean) {
|
||||
this.owner = (EntityBean) ownerBean;
|
||||
this.loadedProps = new boolean[owner._ebean_getPropertyNames().length];
|
||||
this.flags = new byte[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,8 +222,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Check each property to see if the bean is partially loaded.
|
||||
*/
|
||||
public boolean isPartial() {
|
||||
for (boolean loadedProp : loadedProps) {
|
||||
if (!loadedProp) {
|
||||
for (byte flag : flags) {
|
||||
if ((flag & FLAG_LOADED_PROP) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -259,10 +268,10 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return true if only the Id property has been loaded.
|
||||
*/
|
||||
public boolean hasIdOnly(int idIndex) {
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if (i == idIndex) {
|
||||
if (!loadedProps[i]) return false;
|
||||
} else if (loadedProps[i]) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) == 0) return false;
|
||||
} else if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -284,9 +293,9 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (idPos > -1) {
|
||||
// For cases where properties are set on constructor
|
||||
// set every non Id property to unloaded (for lazy loading)
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if (i != idPos) {
|
||||
loadedProps[i] = false;
|
||||
flags[i] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +361,9 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.owner._ebean_setEmbeddedLoaded();
|
||||
this.lazyLoadProperty = -1;
|
||||
this.origValues = null;
|
||||
this.changedProps = null;
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] &= ~(FLAG_CHANGED_PROP + FLAG_ORIG_VALUE_SET);
|
||||
}
|
||||
this.dirty = false;
|
||||
}
|
||||
|
||||
@@ -475,7 +486,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
if (position == -1) {
|
||||
throw new IllegalArgumentException("Property " + propertyName + " not found");
|
||||
}
|
||||
loadedProps[position] = loaded;
|
||||
if (loaded) {
|
||||
flags[position] |= FLAG_LOADED_PROP;
|
||||
} else {
|
||||
flags[position] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -483,22 +498,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* constructor.
|
||||
*/
|
||||
public void setPropertyUnloaded(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = false;
|
||||
flags[propertyIndex] &= ~FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property to be loaded.
|
||||
*/
|
||||
public void setLoadedProperty(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all properties to be loaded (post insert).
|
||||
*/
|
||||
public void setLoadedPropertyAll() {
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
loadedProps[i] = true;
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
flags[i] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,14 +521,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Return true if the property is loaded.
|
||||
*/
|
||||
public boolean isLoadedProperty(int propertyIndex) {
|
||||
return loadedProps[propertyIndex];
|
||||
return (flags[propertyIndex] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is considered changed.
|
||||
*/
|
||||
public boolean isChangedProperty(int propertyIndex) {
|
||||
return (changedProps != null && changedProps[propertyIndex]);
|
||||
return (flags[propertyIndex] & FLAG_CHANGED_PROP) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -521,8 +536,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* embedded properties is dirty.
|
||||
*/
|
||||
public boolean isDirtyProperty(int propertyIndex) {
|
||||
return (changedProps != null && changedProps[propertyIndex]
|
||||
|| embeddedDirty != null && embeddedDirty[propertyIndex]);
|
||||
return (flags[propertyIndex] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,27 +548,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
|
||||
public void setChangedProperty(int propertyIndex) {
|
||||
if (changedProps == null) {
|
||||
changedProps = new boolean[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
changedProps[propertyIndex] = true;
|
||||
flags[propertyIndex] |= FLAG_CHANGED_PROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set that an embedded bean has had one of its properties changed.
|
||||
*/
|
||||
private void setEmbeddedPropertyDirty(int propertyIndex) {
|
||||
if (embeddedDirty == null) {
|
||||
embeddedDirty = new boolean[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
embeddedDirty[propertyIndex] = true;
|
||||
flags[propertyIndex] |= FLAG_EMBEDDED_DIRTY;
|
||||
}
|
||||
|
||||
private void setOriginalValue(int propertyIndex, Object value) {
|
||||
if (origValues == null) {
|
||||
origValues = new Object[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
if (origValues[propertyIndex] == null) {
|
||||
if ((flags[propertyIndex] & FLAG_ORIG_VALUE_SET) == 0) {
|
||||
flags[propertyIndex] |= FLAG_ORIG_VALUE_SET;
|
||||
origValues[propertyIndex] = value;
|
||||
}
|
||||
}
|
||||
@@ -574,13 +583,9 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
*/
|
||||
public void setNewBeanForUpdate() {
|
||||
|
||||
if (changedProps == null) {
|
||||
changedProps = new boolean[owner._ebean_getPropertyNames().length];
|
||||
}
|
||||
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
if (loadedProps[i]) {
|
||||
changedProps[i] = true;
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
flags[i] |= FLAG_CHANGED_PROP;
|
||||
}
|
||||
}
|
||||
setDirty(true);
|
||||
@@ -594,8 +599,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return null;
|
||||
}
|
||||
Set<String> props = new LinkedHashSet<>();
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
if (loadedProps[i]) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
if ((flags[i] & FLAG_LOADED_PROP) != 0) {
|
||||
props.add(getProperty(i));
|
||||
}
|
||||
}
|
||||
@@ -609,12 +614,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
int len = getPropertyLength();
|
||||
boolean[] dirties = new boolean[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
dirties[i] = true;
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
// an embedded property has been changed - recurse
|
||||
dirties[i] = true;
|
||||
}
|
||||
// this, or an embedded property has been changed - recurse
|
||||
dirties[i] = (flags[i] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0;
|
||||
}
|
||||
return dirties;
|
||||
}
|
||||
@@ -634,11 +635,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyNames(Set<String> props, String prefix) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
// the property has been changed on this bean
|
||||
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
|
||||
props.add(propName);
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
|
||||
embeddedBean._ebean_getIntercept().addDirtyPropertyNames(props, getProperty(i) + ".");
|
||||
@@ -654,12 +655,12 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
String[] names = owner._ebean_getPropertyNames();
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
// the property has been changed on this bean
|
||||
if (propertyNames.contains(names[i])) {
|
||||
return true;
|
||||
}
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
if (propertyNames.contains(names[i])) {
|
||||
return true;
|
||||
}
|
||||
@@ -683,15 +684,16 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
// the property has been changed on this bean
|
||||
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
|
||||
Object newVal = owner._ebean_getField(i);
|
||||
Object oldVal = getOrigValue(i);
|
||||
if (!areEqual(oldVal, newVal)) {
|
||||
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
|
||||
}
|
||||
|
||||
dirtyValues.put(propName, new ValuePair(newVal, oldVal));
|
||||
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
|
||||
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i) + ".");
|
||||
@@ -705,13 +707,15 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
// the property has been changed on this bean
|
||||
Object newVal = owner._ebean_getField(i);
|
||||
Object oldVal = getOrigValue(i);
|
||||
visitor.visit(i, newVal, oldVal);
|
||||
if (!areEqual(oldVal, newVal)) {
|
||||
visitor.visit(i, newVal, oldVal);
|
||||
}
|
||||
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
|
||||
visitor.visitPush(i);
|
||||
@@ -739,9 +743,9 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
|
||||
sb.append(i).append(',');
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
|
||||
sb.append(i).append('[');
|
||||
@@ -765,15 +769,12 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of property names for changed properties.
|
||||
*/
|
||||
public boolean[] getChanged() {
|
||||
return changedProps;
|
||||
}
|
||||
|
||||
public boolean[] getLoaded() {
|
||||
return loadedProps;
|
||||
boolean[] ret= new boolean[flags.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -821,7 +822,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
*/
|
||||
private void loadBeanInternal(int loadProperty, BeanLoader loader) {
|
||||
|
||||
if (loadedProps == null || loadedProps[loadProperty]) {
|
||||
if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) {
|
||||
// race condition where multiple threads calling preGetter concurrently
|
||||
return;
|
||||
}
|
||||
@@ -887,7 +888,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Called when a BeanCollection is initialised automatically.
|
||||
*/
|
||||
public void initialisedMany(int propertyIndex) {
|
||||
loadedProps[propertyIndex] = true;
|
||||
flags[propertyIndex] |= FLAG_LOADED_PROP;
|
||||
}
|
||||
|
||||
private void preGetterCallback(int propertyIndex) {
|
||||
|
||||
@@ -273,14 +273,16 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
checkReadOnly();
|
||||
init();
|
||||
if (modifyListening) {
|
||||
Object oldBean = map.put(key, value);
|
||||
E oldBean = map.put(key, value);
|
||||
if (value != oldBean) {
|
||||
// register the add of the new and the removal of the old
|
||||
modifyAddition(value);
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
return oldBean;
|
||||
} else {
|
||||
return map.put(key, value);
|
||||
}
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -295,8 +297,9 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
modifyRemoval(oldBean);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map.putAll(puts);
|
||||
}
|
||||
map.putAll(puts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1965,6 +1965,15 @@ public class ServerConfig {
|
||||
* Return the UUID state file.
|
||||
*/
|
||||
public String getUuidStateFile() {
|
||||
if (uuidStateFile == null || uuidStateFile.isEmpty()) {
|
||||
// by default, add servername...
|
||||
uuidStateFile = name + "-uuid.state";
|
||||
// and store it in the user's home directory
|
||||
String homeDir = System.getProperty("user.home");
|
||||
if (homeDir != null && homeDir.isEmpty()) {
|
||||
uuidStateFile = homeDir + "/.ebean/" + uuidStateFile;
|
||||
}
|
||||
}
|
||||
return uuidStateFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected String closeQuote = "\"";
|
||||
|
||||
protected String concatOperator = "||";
|
||||
|
||||
/**
|
||||
* When set to true all db column names and table names use quoted identifiers.
|
||||
*/
|
||||
@@ -455,13 +453,6 @@ public class DatabasePlatform {
|
||||
return openQuote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DB concat operator.
|
||||
*/
|
||||
public String getConcatOperator() {
|
||||
return concatOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JDBC type used to store booleans.
|
||||
*/
|
||||
|
||||
@@ -9,6 +9,10 @@ import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Information and methods on BeanDescriptors made available to plugins.
|
||||
@@ -18,6 +22,7 @@ public interface BeanType<T> {
|
||||
/**
|
||||
* Return the short name of the bean type.
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
@@ -28,11 +33,13 @@ public interface BeanType<T> {
|
||||
/**
|
||||
* Return the full name of the bean type.
|
||||
*/
|
||||
@Nonnull
|
||||
String getFullName();
|
||||
|
||||
/**
|
||||
* Return the class type this BeanDescriptor describes.
|
||||
*/
|
||||
@Nonnull
|
||||
Class<T> getBeanType();
|
||||
|
||||
/**
|
||||
@@ -43,6 +50,7 @@ public interface BeanType<T> {
|
||||
/**
|
||||
* Return all the properties for this bean type.
|
||||
*/
|
||||
@Nonnull
|
||||
Collection<? extends Property> allProperties();
|
||||
|
||||
/**
|
||||
@@ -197,6 +205,28 @@ public interface BeanType<T> {
|
||||
*/
|
||||
boolean hasInheritance();
|
||||
|
||||
/**
|
||||
* Return true if this object is the root level object in its entity
|
||||
* inheritance.
|
||||
*/
|
||||
boolean isInheritanceRoot();
|
||||
|
||||
/**
|
||||
* Returns all direct children of this beantype
|
||||
*/
|
||||
List<BeanType<?>> getInheritanceChildren();
|
||||
|
||||
/**
|
||||
* Returns the parent in inheritance hiearchy
|
||||
*/
|
||||
BeanType<?> getInheritanceParent();
|
||||
|
||||
/**
|
||||
* Visit all children recursively
|
||||
* @param visitor
|
||||
*/
|
||||
void visitAllInheritanceChildren(Consumer<BeanType<?>> visitor);
|
||||
|
||||
/**
|
||||
* Return the discriminator column.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.plugin;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Property of a entity bean that can be read.
|
||||
*/
|
||||
@@ -8,8 +10,15 @@ public interface Property {
|
||||
/**
|
||||
* Return the name of the property.
|
||||
*/
|
||||
@Nonnull
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the type of the property.
|
||||
*/
|
||||
@Nonnull
|
||||
Class<?> getPropertyType();
|
||||
|
||||
/**
|
||||
* Return the value of the property on the given bean.
|
||||
*/
|
||||
|
||||
@@ -7,8 +7,14 @@ import io.ebeaninternal.server.query.SqlJoinType;
|
||||
*/
|
||||
class AssocOneHelpRefExported extends AssocOneHelp {
|
||||
|
||||
public AssocOneHelpRefExported(BeanPropertyAssocOne<?> property) {
|
||||
private final boolean softDelete;
|
||||
|
||||
private final String softDeletePredicate;
|
||||
|
||||
AssocOneHelpRefExported(BeanPropertyAssocOne<?> property) {
|
||||
super(property);
|
||||
this.softDelete = property.targetDescriptor.isSoftDelete();
|
||||
this.softDeletePredicate = (softDelete) ? property.targetDescriptor.getSoftDeletePredicate("") : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,6 +34,10 @@ class AssocOneHelpRefExported extends AssocOneHelp {
|
||||
void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
|
||||
|
||||
String relativePrefix = ctx.getRelativePrefix(property.getName());
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
if (softDelete && !ctx.isIncludeSoftDelete()) {
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx, softDeletePredicate);
|
||||
} else {
|
||||
property.tableJoin.addJoin(joinType, relativePrefix, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -107,6 +108,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
@@ -1133,6 +1136,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
* Return true if this object is the root level object in its entity
|
||||
* inheritance.
|
||||
*/
|
||||
@Override
|
||||
public boolean isInheritanceRoot() {
|
||||
return inheritInfo == null || inheritInfo.isRoot();
|
||||
}
|
||||
@@ -3475,4 +3479,29 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
public List<BeanProperty[]> getUniqueProps() {
|
||||
return propertiesUnique;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanType<?>> getInheritanceChildren() {
|
||||
if (hasInheritance()) {
|
||||
return getInheritInfo().getChildren()
|
||||
.stream()
|
||||
.map(InheritInfo::desc)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanType<?> getInheritanceParent() {
|
||||
return getInheritInfo() == null ? null : getInheritInfo().getParent().desc();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAllInheritanceChildren(Consumer<BeanType<?>> visitor) {
|
||||
if (hasInheritance()) {
|
||||
getInheritInfo().visitChildren(info -> visitor.accept(info.desc()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -979,6 +979,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
/**
|
||||
* Return the full name of this property.
|
||||
*/
|
||||
@Override
|
||||
public String getFullBeanName() {
|
||||
return descriptor.getFullName() + "." + name;
|
||||
}
|
||||
@@ -994,6 +995,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
/**
|
||||
* Return the scalarType.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
public ScalarType<Object> getScalarType() {
|
||||
return scalarType;
|
||||
@@ -1369,6 +1371,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
|
||||
/**
|
||||
* Return the property type.
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
private List<Object> findIdsByParentIdList(List<Object> parentIds, Transaction t) {
|
||||
|
||||
String rawWhere = deriveWhereParentIdSql(true);
|
||||
String inClause = targetIdBinder.getIdInValueExpr(false, parentIds.size());
|
||||
String inClause = getIdBinder().getIdInValueExpr(false, parentIds.size());
|
||||
String expr = rawWhere + inClause;
|
||||
|
||||
SpiEbeanServer server = server();
|
||||
@@ -537,8 +537,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
BeanProperty[] emIds = targetDesc.propertiesBaseScalar();
|
||||
try {
|
||||
for (BeanProperty emId : emIds) {
|
||||
ExportedProperty expProp = findMatch(true, emId);
|
||||
list.add(expProp);
|
||||
list.add(findMatch(true, emId));
|
||||
}
|
||||
} catch (PersistenceException e) {
|
||||
// not found as individual scalar properties
|
||||
@@ -547,8 +546,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
|
||||
|
||||
} else {
|
||||
if (idProp != null) {
|
||||
ExportedProperty expProp = findMatch(false, idProp);
|
||||
list.add(expProp);
|
||||
list.add(findMatch(false, idProp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ public interface DbSqlContext {
|
||||
*/
|
||||
void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2, String inheritance);
|
||||
|
||||
void pushSecondaryTableAlias(String alias);
|
||||
|
||||
/**
|
||||
* Push the current table alias onto the stack.
|
||||
*/
|
||||
@@ -91,11 +89,6 @@ public interface DbSqlContext {
|
||||
*/
|
||||
String getContent();
|
||||
|
||||
/**
|
||||
* Return the current join node.
|
||||
*/
|
||||
String peekJoin();
|
||||
|
||||
/**
|
||||
* Push a join node onto the stack.
|
||||
*/
|
||||
@@ -125,6 +118,11 @@ public interface DbSqlContext {
|
||||
*/
|
||||
void appendHistorySysPeriod();
|
||||
|
||||
/**
|
||||
* Return true if the query includes soft deleted rows.
|
||||
*/
|
||||
boolean isIncludeSoftDelete();
|
||||
|
||||
/**
|
||||
* Return true if the query is a 'asDraft' query.
|
||||
*/
|
||||
@@ -139,4 +137,5 @@ public interface DbSqlContext {
|
||||
* Append 'for update' lock hints on FROM clause (sql server only).
|
||||
*/
|
||||
void appendFromForUpdate();
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ public abstract class DeployParser {
|
||||
*/
|
||||
protected static final char UNDERSCORE = '_';
|
||||
|
||||
protected static final char OPEN_SQUARE_BRACKET = '[';
|
||||
protected static final char CLOSE_SQUARE_BRACKET = ']';
|
||||
protected static final char DOUBLE_QUOTE = '\"';
|
||||
protected static final char BACK_QUOTE = '`';
|
||||
|
||||
/**
|
||||
* Used to determine when a column name terminates.
|
||||
*/
|
||||
@@ -183,10 +188,10 @@ public abstract class DeployParser {
|
||||
wordBuffer.append(ch);
|
||||
return false;
|
||||
}
|
||||
return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD;
|
||||
return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD || ch == DOUBLE_QUOTE || ch == CLOSE_SQUARE_BRACKET || ch == BACK_QUOTE;
|
||||
}
|
||||
|
||||
private boolean isWordStart(char ch) {
|
||||
return Character.isLetter(ch) || ch == UNDERSCORE;
|
||||
return Character.isLetter(ch) || ch == UNDERSCORE || ch == DOUBLE_QUOTE || ch == OPEN_SQUARE_BRACKET || ch == BACK_QUOTE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +126,16 @@ public final class TableJoin {
|
||||
return type;
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx, String predicate) {
|
||||
String[] names = SplitName.split(prefix);
|
||||
String a1 = ctx.getTableAlias(names[0]);
|
||||
String a2 = ctx.getTableAlias(prefix);
|
||||
|
||||
SqlJoinType returnJoinType = addJoin(joinType, a1, a2, ctx);
|
||||
ctx.append("and ").append(a2).append(predicate);
|
||||
return returnJoinType;
|
||||
}
|
||||
|
||||
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
|
||||
|
||||
String[] names = SplitName.split(prefix);
|
||||
|
||||
@@ -132,6 +132,9 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
// check for manually defined joins
|
||||
BeanTable beanTable = prop.getBeanTable();
|
||||
for (JoinColumn joinColumn : getAll(prop, JoinColumn.class)) {
|
||||
if (beanTable == null) {
|
||||
throw new IllegalStateException("Looks like a missing @ManyToOne or @OneToOne on property " + prop.getFullBeanName()+" - no related 'BeanTable'");
|
||||
}
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
@@ -146,6 +149,9 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
for (JoinColumn joinColumn : joinTable.joinColumns()) {
|
||||
if (beanTable == null) {
|
||||
throw new IllegalStateException("Looks like a missing @ManyToOne or @OneToOne on property " + prop.getFullBeanName()+" - no related 'BeanTable'");
|
||||
}
|
||||
prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable);
|
||||
if (!joinColumn.updatable()) {
|
||||
prop.setDbUpdateable(false);
|
||||
|
||||
@@ -82,12 +82,12 @@ public abstract class AnnotationBase {
|
||||
T a = null;
|
||||
Field field = prop.getField();
|
||||
if (field != null) {
|
||||
a = AnnotationUtil.findAnnotation(field, annClass);
|
||||
a = AnnotationUtil.findAnnotation(field, annClass, platform);
|
||||
}
|
||||
if (a == null) {
|
||||
Method method = prop.getReadMethod();
|
||||
if (method != null) {
|
||||
a = AnnotationUtil.findAnnotation(method, annClass);
|
||||
a = AnnotationUtil.findAnnotation(method, annClass, platform);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
|
||||
@@ -92,14 +92,7 @@ class InPairsExpression extends AbstractExpression {
|
||||
return;
|
||||
}
|
||||
|
||||
String concat = request.getDbPlatformHandler().getConcatOperator();
|
||||
|
||||
String concatFormula = "(" + property0 + concat + "'" + separator + "'" + concat + property1;
|
||||
if (suffix != null && !suffix.isEmpty()) {
|
||||
concatFormula += concat + "'" + suffix + "'";
|
||||
}
|
||||
concatFormula += ")";
|
||||
request.append(concatFormula);
|
||||
request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix));
|
||||
request.appendInExpression(not, concatBindValues);
|
||||
}
|
||||
|
||||
|
||||
@@ -667,7 +667,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public ExpressionList<T> notExists(Query<?> subQuery) {
|
||||
return exprList.exists(subQuery);
|
||||
return exprList.notExists(subQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,17 +8,6 @@ import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
*/
|
||||
abstract class BaseDbExpression implements DbExpressionHandler {
|
||||
|
||||
private final String concatOperator;
|
||||
|
||||
BaseDbExpression(String concatOperator) {
|
||||
this.concatOperator = concatOperator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConcatOperator() {
|
||||
return concatOperator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
|
||||
|
||||
@@ -57,4 +46,14 @@ abstract class BaseDbExpression implements DbExpressionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String concat(String property0, String separator, String property1, String suffix) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("concat(").append(property0).append(",'").append(separator).append("',").append(property1);
|
||||
if (suffix != null && !suffix.isEmpty()) {
|
||||
sb.append(",'").append(suffix).append('\'');
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op;
|
||||
*/
|
||||
public class BasicDbExpression extends BaseDbExpression {
|
||||
|
||||
BasicDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
|
||||
throw new RuntimeException("JSON expressions only supported on Postgres and Oracle");
|
||||
|
||||
@@ -9,11 +9,6 @@ import io.ebeaninternal.server.expression.Op;
|
||||
*/
|
||||
public interface DbExpressionHandler {
|
||||
|
||||
/**
|
||||
* Return the DB concat operator (Usually SQL standard "||").
|
||||
*/
|
||||
String getConcatOperator();
|
||||
|
||||
/**
|
||||
* Write the db platform specific json expression.
|
||||
*/
|
||||
@@ -33,4 +28,9 @@ public interface DbExpressionHandler {
|
||||
* Add the bitwise expression.
|
||||
*/
|
||||
void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match);
|
||||
|
||||
/**
|
||||
* Performs a "CONCAT" operation for that platform.
|
||||
*/
|
||||
String concat(String property0, String separator, String property1, String suffix);
|
||||
}
|
||||
|
||||
+8
-7
@@ -12,20 +12,21 @@ public class DbExpressionHandlerFactory {
|
||||
public static DbExpressionHandler from(DatabasePlatform databasePlatform) {
|
||||
|
||||
Platform platform = databasePlatform.getPlatform();
|
||||
String concatOperator = databasePlatform.getConcatOperator();
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2DbExpression(concatOperator);
|
||||
return new H2DbExpression();
|
||||
case POSTGRES:
|
||||
return new PostgresDbExpression(concatOperator);
|
||||
return new PostgresDbExpression();
|
||||
case MYSQL:
|
||||
return new MySqlDbExpression(concatOperator);
|
||||
return new MySqlDbExpression();
|
||||
case ORACLE:
|
||||
return new OracleDbExpression(concatOperator);
|
||||
return new OracleDbExpression();
|
||||
case SQLSERVER16:
|
||||
case SQLSERVER17:
|
||||
case SQLSERVER:
|
||||
return new SqlServerDbExpression(concatOperator);
|
||||
return new SqlServerDbExpression();
|
||||
default:
|
||||
return new BasicDbExpression(concatOperator);
|
||||
return new BasicDbExpression();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.BitwiseOp;
|
||||
*/
|
||||
class H2DbExpression extends BasicDbExpression {
|
||||
|
||||
H2DbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) {
|
||||
|
||||
|
||||
@@ -5,8 +5,4 @@ package io.ebeaninternal.server.expression.platform;
|
||||
*/
|
||||
class MySqlDbExpression extends BasicDbExpression {
|
||||
|
||||
MySqlDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,10 +9,6 @@ import io.ebeaninternal.server.expression.Op;
|
||||
*/
|
||||
public class OracleDbExpression extends BaseDbExpression {
|
||||
|
||||
OracleDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
|
||||
|
||||
|
||||
+12
-4
@@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op;
|
||||
*/
|
||||
public class PostgresDbExpression extends BaseDbExpression {
|
||||
|
||||
PostgresDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
|
||||
|
||||
@@ -65,4 +61,16 @@ public class PostgresDbExpression extends BaseDbExpression {
|
||||
request.append(" <> 0");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String concat(String property0, String separator, String property1, String suffix) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(").append(property0).append("||'").append(separator).append("'||").append(property1);
|
||||
|
||||
if (suffix != null && !suffix.isEmpty()) {
|
||||
sb.append("||'").append(suffix).append('\'');
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op;
|
||||
*/
|
||||
public class SqlServerDbExpression extends BaseDbExpression {
|
||||
|
||||
SqlServerDbExpression(String concatOperator) {
|
||||
super(concatOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void json(final SpiExpressionRequest request, final String propName,
|
||||
final String path, final Op operator, final Object value) {
|
||||
|
||||
@@ -82,8 +82,17 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
|
||||
final Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
|
||||
while (e.hasMoreElements()) {
|
||||
NetworkInterface network = e.nextElement();
|
||||
if (!network.isLoopback()) {
|
||||
return network.getHardwareAddress();
|
||||
try {
|
||||
logger.trace("Probing interface {}", network);
|
||||
if (!network.isLoopback()) {
|
||||
byte[] addr = network.getHardwareAddress();
|
||||
if (addr != null) {
|
||||
logger.debug("Using interface {}", network);
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
} catch (SocketException ex) {
|
||||
logger.debug("Skipping {}", network, ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -181,6 +190,10 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator {
|
||||
prop.setProperty("nodeId", getNodeIdentifier());
|
||||
prop.setProperty("clockSeq", String.valueOf(clockSeq.get()));
|
||||
prop.setProperty("timeStamp", String.valueOf(timeStamp.get()));
|
||||
File dir = stateFile.getParentFile();
|
||||
if (dir != null) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
try (OutputStream os = new FileOutputStream(stateFile)) {
|
||||
prop.store(os, "ebean uuid state file");
|
||||
logger.debug("Persisted state to '{}'", stateFile);
|
||||
|
||||
@@ -110,7 +110,15 @@ public class BatchedPstmtHolder {
|
||||
// but still need to close PreparedStatements.
|
||||
boolean isError = false;
|
||||
|
||||
for (BatchedPstmt bs : stmtMap.values()) {
|
||||
// if there are Listeners/Controllers that interact with the database,
|
||||
// the flush may get called recursively in executeBatch/postExecute.
|
||||
// which leads that we process stmtMap.values() twice in the loop.
|
||||
// So we copy the values, that we want to flush and clear it immediately.
|
||||
BatchedPstmt[] values = stmtMap.values().toArray(new BatchedPstmt[stmtMap.values().size()]);
|
||||
clear();
|
||||
|
||||
// this loop
|
||||
for (BatchedPstmt bs : values) {
|
||||
try {
|
||||
if (!isError) {
|
||||
bs.executeBatch(getGeneratedKeys);
|
||||
@@ -139,8 +147,6 @@ public class BatchedPstmtHolder {
|
||||
}
|
||||
}
|
||||
|
||||
// clear the batch cache
|
||||
clear();
|
||||
|
||||
if (firstError != null) {
|
||||
String msg = "Error when batch flush on sql: " + errorSql;
|
||||
|
||||
@@ -417,7 +417,9 @@ class CQueryBuilder {
|
||||
|
||||
BeanDescriptor<?> desc = request.getBeanDescriptor();
|
||||
try {
|
||||
PreparedStatement statement = connection.prepareStatement(sql);
|
||||
// For SqlServer we need either "selectMethod=cursor" in the connection string or fetch explicitly a cursorable
|
||||
// statement here by specifying ResultSet.CONCUR_UPDATABLE
|
||||
PreparedStatement statement = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
|
||||
predicates.bind(statement, connection);
|
||||
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
@@ -70,6 +70,11 @@ class DefaultDbSqlContext implements DbSqlContext {
|
||||
this.fromForUpdate = fromForUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludeSoftDelete() {
|
||||
return alias.isIncludeSoftDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendFromForUpdate() {
|
||||
if (fromForUpdate != null) {
|
||||
@@ -99,11 +104,6 @@ class DefaultDbSqlContext implements DbSqlContext {
|
||||
return encryptedProps.toArray(new BeanProperty[encryptedProps.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String peekJoin() {
|
||||
return joinStack.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popJoin() {
|
||||
joinStack.pop();
|
||||
@@ -206,11 +206,6 @@ class DefaultDbSqlContext implements DbSqlContext {
|
||||
return alias.getTableAliasManyWhere(prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushSecondaryTableAlias(String alias) {
|
||||
tableAliasStack.push(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRelativePrefix(String propName) {
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -17,6 +18,8 @@ class SqlTreeAlias {
|
||||
|
||||
private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL);
|
||||
|
||||
private final SpiQuery.TemporalMode temporalMode;
|
||||
|
||||
private int counter;
|
||||
|
||||
private int manyWhereCounter;
|
||||
@@ -33,8 +36,9 @@ class SqlTreeAlias {
|
||||
|
||||
private final String rootTableAlias;
|
||||
|
||||
SqlTreeAlias(String rootTableAlias) {
|
||||
SqlTreeAlias(String rootTableAlias, SpiQuery.TemporalMode temporalMode) {
|
||||
this.rootTableAlias = rootTableAlias;
|
||||
this.temporalMode = temporalMode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,4 +215,8 @@ class SqlTreeAlias {
|
||||
boolean isIncludeJoins() {
|
||||
return !aliasMap.isEmpty() || !manyWhereAliasMap.isEmpty();
|
||||
}
|
||||
|
||||
boolean isIncludeSoftDelete() {
|
||||
return temporalMode == SpiQuery.TemporalMode.SOFT_DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public final class SqlTreeBuilder {
|
||||
this.queryDetail = query.getDetail();
|
||||
|
||||
this.predicates = predicates;
|
||||
this.alias = new SqlTreeAlias(request.getBaseTableAlias());
|
||||
this.alias = new SqlTreeAlias(request.getBaseTableAlias(), temporalMode);
|
||||
this.distinctOnPlatform = builder.isPlatformDistinctOn();
|
||||
|
||||
String fromForUpdate = builder.fromForUpdate(query);
|
||||
|
||||
@@ -51,6 +51,7 @@ public class ScalarTypeLocalTime extends ScalarTypeBase<LocalTime> {
|
||||
@Override
|
||||
public LocalTime toBeanType(Object value) {
|
||||
if (value instanceof LocalTime) return (LocalTime) value;
|
||||
if (value == null) return null;
|
||||
return BasicTypeConverter.toTime(value).toLocalTime();
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class ScalarTypeLocalTimeWithNanos extends ScalarTypeLocalTime {
|
||||
@Override
|
||||
public LocalTime toBeanType(Object value) {
|
||||
if (value instanceof LocalTime) return (LocalTime) value;
|
||||
if (value == null) return null;
|
||||
return LocalTime.ofNanoOfDay(BasicTypeConverter.toLong(value));
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ public class ScalarTypeMonthDay extends ScalarTypeBase<MonthDay> {
|
||||
@Override
|
||||
public MonthDay toBeanType(Object value) {
|
||||
if (value instanceof MonthDay) return (MonthDay) value;
|
||||
if (value == null) return null;
|
||||
return convertFromDate((Date) value);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,16 +13,16 @@ if not exists (select name from sys.types where name = 'ebean_uniqueidentifier_
|
||||
if not exists (select name from sys.types where name = 'ebean_nvarchar_tvp') create type ebean_nvarchar_tvp as table (c1 nvarchar(max));
|
||||
|
||||
delimiter $$
|
||||
-----------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_indices TABLE, COLUMN
|
||||
-- deletes all indices referring to TABLE.COLUMN
|
||||
-----------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_indices @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
declare @indexName nvarchar(255)
|
||||
BEGIN
|
||||
DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i
|
||||
DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i
|
||||
join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id
|
||||
join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id
|
||||
where i.object_id = OBJECT_ID(@tableName) AND c.name = @columnName;
|
||||
@@ -41,10 +41,10 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_default_constraint TABLE, COLUMN
|
||||
-- deletes the default constraint, which has a random name
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_default_constraint @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @tmp nvarchar(1000)
|
||||
@@ -58,16 +58,16 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_constraints TABLE, COLUMN
|
||||
-- deletes constraints and foreign keys refering to TABLE.COLUMN
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_constraints @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
declare @constraintName nvarchar(255)
|
||||
BEGIN
|
||||
DECLARE name_cursor CURSOR FOR
|
||||
DECLARE name_cursor CURSOR FOR
|
||||
SELECT cc.name from sys.check_constraints cc
|
||||
join sys.columns c on c.object_id = cc.parent_object_id and c.column_id = cc.parent_column_id
|
||||
where parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName
|
||||
@@ -92,10 +92,10 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
|
||||
-- deletes the column annd ensures that all indices and constraints are dropped first
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_column @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
@@ -114,21 +114,21 @@ $$
|
||||
DROP PROCEDURE IF EXISTS usp_ebean_drop_foreign_keys;
|
||||
|
||||
delimiter $$
|
||||
------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN
|
||||
-- deletes all constraints and foreign keys referring to TABLE.COLUMN
|
||||
------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE PROCEDURE usp_ebean_drop_foreign_keys(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT FALSE;
|
||||
DECLARE c_fk_name CHAR(255);
|
||||
DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE
|
||||
DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE() and TABLE_NAME = p_table_name and COLUMN_NAME = p_column_name
|
||||
AND REFERENCED_TABLE_NAME IS NOT NULL;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||
|
||||
OPEN curs;
|
||||
|
||||
|
||||
read_loop: LOOP
|
||||
FETCH curs INTO c_fk_name;
|
||||
IF done THEN
|
||||
@@ -138,7 +138,7 @@ BEGIN
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
END LOOP;
|
||||
|
||||
|
||||
CLOSE curs;
|
||||
END
|
||||
$$
|
||||
@@ -146,10 +146,10 @@ $$
|
||||
DROP PROCEDURE IF EXISTS usp_ebean_drop_column;
|
||||
|
||||
delimiter $$
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
|
||||
-- deletes the column and ensures that all indices and constraints are dropped first
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE PROCEDURE usp_ebean_drop_column(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
|
||||
BEGIN
|
||||
CALL usp_ebean_drop_foreign_keys(p_table_name, p_column_name);
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Address;
|
||||
import org.tests.model.basic.BWithQIdent;
|
||||
import org.tests.model.basic.Customer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -14,6 +17,8 @@ public class DeployPropertyParserTest extends BaseTestCase {
|
||||
|
||||
private final BeanDescriptor<Address> addressBeanDescriptor = getBeanDescriptor(Address.class);
|
||||
|
||||
private final BeanDescriptor<BWithQIdent> bWithQIdentDescriptor = getBeanDescriptor(BWithQIdent.class);
|
||||
|
||||
@Test
|
||||
public void from_prefix_expect_unchanged() {
|
||||
assertThat(parser().parse("(select x from status join status)")).isEqualTo("(select x from status join status)");
|
||||
@@ -49,6 +54,31 @@ public class DeployPropertyParserTest extends BaseTestCase {
|
||||
assertThat(addressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withExplicitQuote_all_platforms() {
|
||||
assertThat(withQuoteParser().parse("t0.`CODE` like ?")).isEqualTo("t0.`CODE` like ?");
|
||||
assertThat(withQuoteParser().parse("t0.[CODE] like ?")).isEqualTo("t0.[CODE] like ?");
|
||||
assertThat(withQuoteParser().parse("t0.\"CODE\" like ?")).isEqualTo("t0.\"CODE\" like ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(value = {Platform.H2, Platform.POSTGRES})
|
||||
public void withQuote_when_match_h2() {
|
||||
assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}\"Name\" like ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(value = Platform.SQLSERVER)
|
||||
public void withQuote_when_match_sqlserver() {
|
||||
assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}[Name] like ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForPlatform(value = Platform.MYSQL)
|
||||
public void withQuote_when_match_mysql() {
|
||||
assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}`Name` like ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknown_path() {
|
||||
assertThat(parser().parse(" foo ")).isEqualTo(" foo ");
|
||||
@@ -62,4 +92,8 @@ public class DeployPropertyParserTest extends BaseTestCase {
|
||||
return addressBeanDescriptor.parser();
|
||||
}
|
||||
|
||||
private DeployPropertyParser withQuoteParser() {
|
||||
return bWithQIdentDescriptor.parser();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class TestQueryCacheTableDependency extends BaseTestCase {
|
||||
.findCount();
|
||||
assertThat(custs).isEqualTo(1);
|
||||
|
||||
Ebean.createSqlUpdate("update O_ADDRESS set line_2=? where line_2=?")
|
||||
Ebean.createSqlUpdate("update o_address set line_2=? where line_2=?")
|
||||
.setNextParameter("St Lucky3")
|
||||
.setNextParameter("St Lucky2")
|
||||
.execute();
|
||||
|
||||
@@ -5,11 +5,13 @@ import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.annotation.ChangeLog;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.event.BeanPersistRequest;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.changelog.ChangeSet;
|
||||
import io.ebean.event.changelog.ChangeType;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.tests.model.basic.EBasicChangeLog;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@@ -18,8 +20,12 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestChangeLog extends BaseTestCase {
|
||||
|
||||
TDChangeLogPrepare changeLogPrepare = new TDChangeLogPrepare();
|
||||
@@ -47,14 +53,77 @@ public class TestChangeLog extends BaseTestCase {
|
||||
bean.setName("logBean");
|
||||
bean.setShortDescription("hello");
|
||||
server.save(bean);
|
||||
BeanChange change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.INSERT);
|
||||
assertThat(change.getData())
|
||||
.contains("\"name\":\"logBean\"")
|
||||
.contains("\"shortDescription\":\"hello\"");
|
||||
|
||||
|
||||
bean.setName("ChangedName");
|
||||
server.save(bean);
|
||||
|
||||
change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.UPDATE);
|
||||
assertThat(change.getOldData()).contains("\"name\":\"logBean\"");
|
||||
assertThat(change.getData()) .contains("\"name\":\"ChangedName\"");
|
||||
|
||||
|
||||
server.delete(bean);
|
||||
|
||||
change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.DELETE);
|
||||
assertThat(change.getData()).isNull();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithNull() {
|
||||
|
||||
EBasicChangeLog bean = new EBasicChangeLog();
|
||||
bean.setName(null);
|
||||
bean.setShortDescription("hello");
|
||||
server.save(bean);
|
||||
BeanChange change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.INSERT);
|
||||
assertThat(change.getData())
|
||||
.doesNotContain("\"name\"")
|
||||
.contains("\"shortDescription\":\"hello\"");
|
||||
|
||||
|
||||
bean.setName("log");
|
||||
bean.setName("logBean");
|
||||
bean.setShortDescription("world");
|
||||
bean.setShortDescription("hello");
|
||||
server.save(bean);
|
||||
|
||||
change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.UPDATE);
|
||||
assertThat(change.getOldData())
|
||||
.contains("\"name\":null") // it was null
|
||||
.doesNotContain("\"shortDescription\""); // it is unchanged
|
||||
|
||||
assertThat(change.getData())
|
||||
.contains("\"name\":\"logBean\"")
|
||||
.doesNotContain("\"shortDescription\""); // it is unchanged
|
||||
|
||||
|
||||
server.delete(bean);
|
||||
|
||||
change = changeLogListener.changes.getChanges().get(0);
|
||||
|
||||
assertThat(change.getEvent()).isEqualTo(ChangeType.DELETE);
|
||||
assertThat(change.getData()).isNull();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private SpiEbeanServer getServer() {
|
||||
|
||||
System.setProperty("ebean.ignoreExtraDdl", "true");
|
||||
|
||||
@@ -5,7 +5,6 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
@Entity
|
||||
@@ -18,6 +17,9 @@ public class BWithQIdent {
|
||||
@Size(max = 191) // key must not exceed 767 Bytes, so max key len for mysql with utf8mb4 = 191*4 = 764 bytes
|
||||
String name;
|
||||
|
||||
@Column(name = "`CODE`")
|
||||
String CODE;
|
||||
|
||||
@Version
|
||||
Timestamp lastUpdated;
|
||||
|
||||
@@ -37,6 +39,14 @@ public class BWithQIdent {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getCODE() {
|
||||
return CODE;
|
||||
}
|
||||
|
||||
public void setCODE(String CODE) {
|
||||
this.CODE = CODE;
|
||||
}
|
||||
|
||||
public Timestamp getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
+8
-8
@@ -4,8 +4,6 @@ import io.ebean.BaseTestCase;
|
||||
import io.ebean.CacheMode;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Pairs;
|
||||
import io.ebean.annotation.IgnorePlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.cache.ServerCache;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.cache.ServerCacheStatistics;
|
||||
@@ -251,7 +249,6 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
|
||||
assertBeanCacheHitMiss(0, 0);
|
||||
}
|
||||
|
||||
@IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER})
|
||||
@Test
|
||||
public void findList_inPairs_standardConcat() {
|
||||
|
||||
@@ -280,14 +277,15 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
|
||||
assertBeanCacheHitMiss(1, 0);
|
||||
|
||||
if (isH2()) {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})");
|
||||
} else if (isPostgres()) {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER})
|
||||
@Test
|
||||
public void findList_inPairs_userConcat() {
|
||||
|
||||
@@ -318,9 +316,11 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
|
||||
assertBeanCacheHitMiss(1, 0);
|
||||
|
||||
if (isH2()) {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})");
|
||||
} else if (isPostgres()){
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')");
|
||||
} else {
|
||||
assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo')");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import java.util.Objects;
|
||||
@Embeddable
|
||||
public class CkeUserKey {
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "cod_cpny")
|
||||
private int codCompany;
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
@Basic(optional = false)
|
||||
@Column(name = "cod_cpny")
|
||||
private int codCompany;
|
||||
|
||||
public CkeUserKey(int codCompany, String username) {
|
||||
this.codCompany = codCompany;
|
||||
this.username = username;
|
||||
|
||||
@@ -2,12 +2,12 @@ package org.tests.model.history;
|
||||
|
||||
import io.ebean.annotation.History;
|
||||
import io.ebean.annotation.HistoryExclude;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
import org.tests.model.draftable.BaseDomain;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@History
|
||||
@@ -21,6 +21,9 @@ public class HeLink extends BaseDomain {
|
||||
|
||||
String comments;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
@HistoryExclude
|
||||
@ManyToMany
|
||||
List<HeDoc> docs;
|
||||
@@ -33,6 +36,14 @@ public class HeLink extends BaseDomain {
|
||||
public HeLink() {
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ import io.ebean.annotation.Platform;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.StrictAssertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestHistoryExclude extends BaseTestCase {
|
||||
|
||||
@@ -28,6 +29,21 @@ public class TestHistoryExclude extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSoftDelete() {
|
||||
|
||||
HeLink l = new HeLink("two", "boo");
|
||||
Ebean.save(l);
|
||||
|
||||
Ebean.delete(l);
|
||||
|
||||
List<HeLink> list = Ebean.find(HeLink.class)
|
||||
.setIncludeSoftDeletes()
|
||||
.findList();
|
||||
|
||||
assertThat(list).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoad() {
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package org.tests.model.onetoone;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
|
||||
@Entity
|
||||
public class OtoBChild {
|
||||
@@ -16,7 +16,7 @@ public class OtoBChild {
|
||||
String child;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "master_id", referencedColumnName = "id")
|
||||
@PrimaryKeyJoinColumn
|
||||
OtoBMaster master;
|
||||
|
||||
public Long getId() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.tests.model.onetoone;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class OtoBMaster {
|
||||
|
||||
String name;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "master")
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "master", fetch = FetchType.LAZY)
|
||||
OtoBChild child;
|
||||
|
||||
public Long getId() {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import io.ebean.Finder;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
public class OtoSdChild {
|
||||
|
||||
public static Finder<Long, OtoSdChild> find = new Finder<>(OtoSdChild.class);
|
||||
|
||||
@Id
|
||||
long id;
|
||||
|
||||
String child;
|
||||
|
||||
@SoftDelete
|
||||
boolean deleted;
|
||||
|
||||
@OneToOne
|
||||
OtoSdMaster master;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public OtoSdChild(String child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(String child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public OtoSdMaster getMaster() {
|
||||
return master;
|
||||
}
|
||||
|
||||
public void setMaster(OtoSdMaster master) {
|
||||
this.master = master;
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import io.ebean.Finder;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Version;
|
||||
|
||||
@Entity
|
||||
public class OtoSdMaster {
|
||||
|
||||
public static Finder<Long, OtoSdMaster> find = new Finder<>(OtoSdMaster.class);
|
||||
|
||||
@Id
|
||||
long id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, mappedBy = "master")//, fetch = FetchType.LAZY)
|
||||
OtoSdChild child;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
public OtoSdMaster(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public OtoSdChild getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(OtoSdChild child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,53 @@ package org.tests.model.onetoone;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.Query;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestOneToOneImportedPkNative extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void findWithLazyOneToOne() {
|
||||
|
||||
OtoBChild child = new OtoBChild();
|
||||
child.setChild("c1");
|
||||
|
||||
OtoBMaster master = new OtoBMaster();
|
||||
master.setName("m2");
|
||||
master.setChild(child);
|
||||
|
||||
Ebean.save(master);
|
||||
|
||||
Query<OtoBMaster> query = Ebean.find(OtoBMaster.class)
|
||||
//.select("name")
|
||||
.where().idEq(master.getId())
|
||||
.query();
|
||||
|
||||
OtoBMaster one = query.findOne();
|
||||
|
||||
String sql = sqlOf(query);
|
||||
assertThat(sql).contains("select t0.id, t0.name from oto_bmaster t0 where t0.id ");
|
||||
assertThat(sql).doesNotContain("left join oto_bchild");
|
||||
|
||||
assertThat(one).isNotNull();
|
||||
|
||||
LoggedSqlCollector.start();
|
||||
|
||||
OtoBChild child1 = one.getChild();
|
||||
assertThat(child1).isNotNull();
|
||||
assertThat(child1.getChild()).isEqualTo("c1");
|
||||
|
||||
List<String> lazyLoadSql = LoggedSqlCollector.stop();
|
||||
assertThat(lazyLoadSql).hasSize(2);
|
||||
assertThat(lazyLoadSql.get(0)).contains("select t0.id, t0.name, t0.id from oto_bmaster t0 where t0.id = ?");
|
||||
assertThat(lazyLoadSql.get(1)).contains("select t0.master_id, t0.child, t0.master_id from oto_bchild t0 where t0.master_id = ?");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void native_with_o2oAndImportedPrimaryKey() {
|
||||
|
||||
@@ -23,12 +64,10 @@ public class TestOneToOneImportedPkNative extends BaseTestCase {
|
||||
|
||||
assertThat(m.getId()).isEqualTo(one.getId());
|
||||
assertThat(m.getName()).isEqualTo(one.getName());
|
||||
assertThat(m.getChild()).isNull();
|
||||
|
||||
OtoBMaster m2 = server.find(OtoBMaster.class, one.getId());
|
||||
assertThat(m2.getId()).isEqualTo(one.getId());
|
||||
assertThat(m2.getName()).isEqualTo(one.getName());
|
||||
assertThat(m2.getChild()).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.tests.model.onetoone;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class TestOneToOneSoftDeleteChild extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void deleteChild() {
|
||||
|
||||
|
||||
OtoSdChild child = new OtoSdChild("c1");
|
||||
OtoSdMaster master = new OtoSdMaster("m1");
|
||||
master.setChild(child);
|
||||
|
||||
Ebean.save(master);
|
||||
|
||||
|
||||
verifyBeforeDelete(master, child);
|
||||
|
||||
Ebean.delete(child);
|
||||
|
||||
verifyAfterDelete(master, child);
|
||||
}
|
||||
|
||||
private void verifyBeforeDelete(OtoSdMaster parent, OtoSdChild child) {
|
||||
assertThat(OtoSdMaster.find.byId(parent.getId()).getChild().getId())
|
||||
.isEqualTo(child.getId());
|
||||
|
||||
assertThat(
|
||||
OtoSdChild.find.byId(child.getId()).getMaster().getId())
|
||||
.isEqualTo(parent.getId());
|
||||
}
|
||||
|
||||
private void verifyAfterDelete(OtoSdMaster parent, OtoSdChild child) {
|
||||
// After delete, finding child by id should return null
|
||||
assertThat(OtoSdChild.find.byId(child.getId()))
|
||||
.isNull();
|
||||
|
||||
// After delete, getting linked child from parent should return null
|
||||
assertThat(OtoSdMaster.find.byId(parent.getId()).getChild())
|
||||
.isNull();
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,13 @@ import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import java.nio.file.Path;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Month;
|
||||
import java.time.MonthDay;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.Period;
|
||||
import java.time.Year;
|
||||
@@ -39,6 +42,9 @@ public class SomeNewTypesBean {
|
||||
@Column(name = "yr_mth")
|
||||
YearMonth yearMonth;
|
||||
|
||||
@Column(name = "month_day")
|
||||
MonthDay monthDay;
|
||||
|
||||
LocalDate localDate;
|
||||
|
||||
LocalDateTime localDateTime;
|
||||
@@ -47,6 +53,8 @@ public class SomeNewTypesBean {
|
||||
|
||||
ZonedDateTime zonedDateTime;
|
||||
|
||||
LocalTime localTime;
|
||||
|
||||
Instant instant;
|
||||
|
||||
ZoneId zoneId;
|
||||
@@ -57,6 +65,8 @@ public class SomeNewTypesBean {
|
||||
|
||||
Period period;
|
||||
|
||||
Duration duration;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -105,6 +115,14 @@ public class SomeNewTypesBean {
|
||||
this.yearMonth = yearMonth;
|
||||
}
|
||||
|
||||
public MonthDay getMonthDay() {
|
||||
return monthDay;
|
||||
}
|
||||
|
||||
public void setMonthDay(MonthDay monthDay) {
|
||||
this.monthDay = monthDay;
|
||||
}
|
||||
|
||||
public LocalDate getLocalDate() {
|
||||
return localDate;
|
||||
}
|
||||
@@ -137,6 +155,14 @@ public class SomeNewTypesBean {
|
||||
this.zonedDateTime = zonedDateTime;
|
||||
}
|
||||
|
||||
public LocalTime getLocalTime() {
|
||||
return localTime;
|
||||
}
|
||||
|
||||
public void setLocalTime(LocalTime localTime) {
|
||||
this.localTime = localTime;
|
||||
}
|
||||
|
||||
public Instant getInstant() {
|
||||
return instant;
|
||||
}
|
||||
@@ -176,4 +202,12 @@ public class SomeNewTypesBean {
|
||||
public void setPeriod(Period period) {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public Duration getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(Duration duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.tests.model.uuidsibling;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.hamcrest.core.IsNull.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class SoftDeleteCascadeTest {
|
||||
|
||||
@Test
|
||||
public void testDeleteParent() {
|
||||
// Insert + link records
|
||||
USibParent parent = new USibParent();
|
||||
parent.save();
|
||||
|
||||
USibChild child = new USibChild(parent);
|
||||
child.save();
|
||||
|
||||
USibChildSibling childSibling = new USibChildSibling(child);
|
||||
childSibling.save();
|
||||
|
||||
Long parentId = parent.getId();
|
||||
UUID childId = child.getId();
|
||||
Long childSiblingId = childSibling.getId();
|
||||
|
||||
assertBefore(parent, child, childSibling);
|
||||
parent.delete();
|
||||
assertAfter(parentId, childId, childSiblingId);
|
||||
}
|
||||
|
||||
private void assertBefore(USibParent parent, USibChild child, USibChildSibling childSibling) {
|
||||
|
||||
parent.refresh();
|
||||
|
||||
assertThat("Parent should have one child loaded",
|
||||
parent.getChildren().size(),
|
||||
is(1)
|
||||
);
|
||||
|
||||
assertThat("Parent should have correct child loaded",
|
||||
parent.getChildren().get(0).getId(),
|
||||
is(child.getId())
|
||||
);
|
||||
|
||||
assertThat("Child that was loaded should have its sibling available",
|
||||
parent.getChildren().get(0).getChildSibling(),
|
||||
not(nullValue())
|
||||
);
|
||||
|
||||
assertThat(
|
||||
"Child that was loaded should have loaded correct sibling",
|
||||
parent.getChildren().get(0).getChildSibling().getId(),
|
||||
is(childSibling.getId())
|
||||
);
|
||||
}
|
||||
|
||||
private void assertAfter(Long parentId, UUID childId, Long childSiblingId) {
|
||||
assertThat(USibParent.find.byId(parentId), is(nullValue()));
|
||||
assertThat(USibChild.find.byId(childId), is(nullValue()));
|
||||
assertThat(USibChildSibling.find.byId(childSiblingId), is(nullValue()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.tests.model.uuidsibling;
|
||||
|
||||
import io.ebean.Finder;
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Entity
|
||||
public class USibChild extends Model {
|
||||
|
||||
private static final long serialVersionUID = 738194912181571389L;
|
||||
|
||||
@Id
|
||||
private UUID id;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
@OneToOne(mappedBy = "child", cascade = CascadeType.REMOVE)
|
||||
private USibChildSibling childSibling;
|
||||
|
||||
@ManyToOne
|
||||
private USibParent parent;
|
||||
|
||||
public static Finder<UUID, USibChild> find = new Finder<>(USibChild.class);
|
||||
|
||||
public USibChild() {}
|
||||
|
||||
public USibChild(USibParent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public USibChildSibling getChildSibling() {
|
||||
return childSibling;
|
||||
}
|
||||
|
||||
public USibChild setChildSibling(USibChildSibling childSibling) {
|
||||
this.childSibling = childSibling;
|
||||
return this;
|
||||
}
|
||||
|
||||
public USibParent getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(USibParent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.tests.model.uuidsibling;
|
||||
|
||||
import io.ebean.Finder;
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Entity
|
||||
public class USibChildSibling extends Model {
|
||||
|
||||
private static final long serialVersionUID = 738194912181571389L;
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
@OneToOne
|
||||
private USibChild child;
|
||||
|
||||
public static Finder<Long, USibChildSibling> find = new Finder<>(USibChildSibling.class);
|
||||
|
||||
public USibChildSibling() {}
|
||||
|
||||
public USibChildSibling(USibChild child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
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 USibChild getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public USibChildSibling setChild(USibChild child) {
|
||||
this.child = child;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.tests.model.uuidsibling;
|
||||
|
||||
import io.ebean.Finder;
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.SoftDelete;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
@Entity
|
||||
public class USibParent extends Model {
|
||||
|
||||
private static final long serialVersionUID = 4116545858939406149L;
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@SoftDelete
|
||||
private boolean deleted;
|
||||
|
||||
@OneToMany(cascade = CascadeType.REMOVE, mappedBy = "parent")
|
||||
private List<USibChild> children;
|
||||
|
||||
public static Finder<Long, USibParent> find = new Finder<>(USibParent.class);
|
||||
|
||||
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 List<USibChild> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public USibParent setChildren(List<USibChild> children) {
|
||||
this.children = children;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.tests.quotedidentifier;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.BWithQIdent;
|
||||
|
||||
public class TestQuotedIdentifierQuery extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
BWithQIdent bean = new BWithQIdent();
|
||||
bean.setName("foo");
|
||||
bean.setCODE("bar");
|
||||
|
||||
Ebean.save(bean);
|
||||
|
||||
Ebean.find(BWithQIdent.class)
|
||||
.where()
|
||||
.eq("name", "foo")
|
||||
.raw("t0.\"Name\" = ?", "foo")
|
||||
.raw("t0.\"CODE\" = ?", "bar")
|
||||
.findList();
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ public class TestNativeSqlBasic extends BaseTestCase {
|
||||
* Oracle does not support getTableName() via JDBC resultSet meta data
|
||||
*/
|
||||
@Test
|
||||
@IgnorePlatform({Platform.SQLSERVER, Platform.ORACLE}) // does only work in 'cursor' mode!
|
||||
@IgnorePlatform({Platform.ORACLE})
|
||||
public void partialAssoc() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
@@ -20,7 +20,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
|
||||
/**
|
||||
* MySql only supports named savepoints - review.
|
||||
*/
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
@IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER})
|
||||
@Test
|
||||
public void ebeanServer_commitTransaction_expect_sameAsTransactionCommit() {
|
||||
|
||||
@@ -65,7 +65,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
|
||||
}
|
||||
|
||||
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL})
|
||||
@Test
|
||||
public void nestedUseSavepoint_doubleNested_rollbackCommit() {
|
||||
|
||||
@@ -102,7 +102,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL})
|
||||
@Test
|
||||
public void nestedUseSavepoint_doubleNested_commitRollback() {
|
||||
|
||||
@@ -139,7 +139,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL})
|
||||
@Test
|
||||
public void nestedUseSavepoint_nested_RequiresNew() {
|
||||
|
||||
@@ -175,7 +175,7 @@ public class TestNestedSubTransaction extends BaseTestCase {
|
||||
assertNull(after);
|
||||
}
|
||||
|
||||
@IgnorePlatform(Platform.MYSQL)
|
||||
@IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL})
|
||||
@Test
|
||||
public void nestedUseSavepoint() {
|
||||
|
||||
|
||||
@@ -11,10 +11,13 @@ import org.tests.model.types.SomeNewTypesBean;
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Month;
|
||||
import java.time.MonthDay;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.Period;
|
||||
import java.time.Year;
|
||||
@@ -37,6 +40,7 @@ public class TestNewTypes extends BaseTestCase {
|
||||
bean.setLocalDateTime(LocalDateTime.now());
|
||||
bean.setOffsetDateTime(OffsetDateTime.now());
|
||||
bean.setZonedDateTime(ZonedDateTime.now());
|
||||
bean.setLocalTime(LocalTime.now());
|
||||
bean.setInstant(Instant.now());
|
||||
bean.setYear(Year.now());
|
||||
bean.setMonth(Month.APRIL);
|
||||
@@ -44,8 +48,10 @@ public class TestNewTypes extends BaseTestCase {
|
||||
bean.setZoneId(ZoneId.systemDefault());
|
||||
bean.setZoneOffset(ZonedDateTime.now().getOffset());
|
||||
bean.setYearMonth(YearMonth.of(2014, 9));
|
||||
bean.setMonthDay(MonthDay.of(9,22));
|
||||
bean.setPath(Paths.get(TEMP_PATH));
|
||||
bean.setPeriod(Period.of(4,3,2));
|
||||
bean.setDuration(Duration.ofMinutes(5));
|
||||
|
||||
|
||||
Ebean.save(bean);
|
||||
@@ -70,6 +76,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().lt("zonedDateTime", ZonedDateTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("localTime", LocalTime.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("zoneId", ZoneId.systemDefault().getId()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
@@ -79,6 +88,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("yearMonth", YearMonth.of(2014, 9)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("monthDay", MonthDay.of(9,22)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().le("year", Year.now()).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
@@ -91,6 +103,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
list = Ebean.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList();
|
||||
assertTrue(!list.isEmpty());
|
||||
|
||||
SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId());
|
||||
|
||||
assertEquals(bean.getZoneId(), fetched.getZoneId());
|
||||
@@ -98,12 +113,15 @@ public class TestNewTypes extends BaseTestCase {
|
||||
assertEquals(bean.getMonth(), fetched.getMonth());
|
||||
assertEquals(bean.getYear(), fetched.getYear());
|
||||
assertEquals(bean.getYearMonth(), fetched.getYearMonth());
|
||||
assertEquals(bean.getMonthDay(), fetched.getMonthDay());
|
||||
assertEquals(bean.getLocalDate(), fetched.getLocalDate());
|
||||
assertThat(fetched.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime());
|
||||
assertThat(fetched.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime());
|
||||
assertThat(fetched.getLocalTime().toSecondOfDay()).isEqualTo(bean.getLocalTime().toSecondOfDay());
|
||||
assertEquals(bean.getInstant().toEpochMilli() / 1000, fetched.getInstant().toEpochMilli() / 1000);
|
||||
assertEquals(bean.getPath(), fetched.getPath());
|
||||
assertEquals(bean.getPeriod(), fetched.getPeriod());
|
||||
assertEquals(bean.getDuration(), fetched.getDuration());
|
||||
|
||||
|
||||
String asJson = Ebean.json().toJson(fetched);
|
||||
@@ -115,13 +133,16 @@ public class TestNewTypes extends BaseTestCase {
|
||||
assertEquals(bean.getMonth(), toBean.getMonth());
|
||||
assertEquals(bean.getYear(), toBean.getYear());
|
||||
assertEquals(bean.getYearMonth(), toBean.getYearMonth());
|
||||
assertEquals(bean.getMonthDay(), toBean.getMonthDay());
|
||||
assertEquals(bean.getLocalDate(), toBean.getLocalDate());
|
||||
assertThat(toBean.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime());
|
||||
assertThat(toBean.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime());
|
||||
assertEquals(bean.getLocalTime().toSecondOfDay(), toBean.getLocalTime().toSecondOfDay());
|
||||
assertEquals(bean.getInstant().toEpochMilli() / 1000, toBean.getInstant().toEpochMilli() / 1000);
|
||||
// FIXME: This test fails on Windows with: expected:<\tmp> but was:<C:\tmp>
|
||||
assertEquals(bean.getPath(), toBean.getPath());
|
||||
assertEquals(bean.getPeriod(), toBean.getPeriod());
|
||||
assertEquals(bean.getDuration(), toBean.getDuration());
|
||||
|
||||
}
|
||||
|
||||
@@ -139,12 +160,15 @@ public class TestNewTypes extends BaseTestCase {
|
||||
assertNull(fetched.getMonth());
|
||||
assertNull(fetched.getYear());
|
||||
assertNull(fetched.getYearMonth());
|
||||
assertNull(fetched.getMonthDay());
|
||||
assertNull(fetched.getLocalDate());
|
||||
assertNull(fetched.getLocalDateTime());
|
||||
assertNull(fetched.getOffsetDateTime());
|
||||
assertNull(fetched.getLocalTime());
|
||||
assertNull(fetched.getInstant());
|
||||
assertNull(fetched.getPath());
|
||||
assertNull(fetched.getPeriod());
|
||||
assertNull(fetched.getDuration());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -154,6 +178,7 @@ public class TestNewTypes extends BaseTestCase {
|
||||
refBean.setLocalDateTime(LocalDateTime.now());
|
||||
refBean.setOffsetDateTime(OffsetDateTime.now());
|
||||
refBean.setZonedDateTime(ZonedDateTime.now());
|
||||
refBean.setLocalTime(LocalTime.now());
|
||||
refBean.setInstant(Instant.now());
|
||||
refBean.setYear(Year.now());
|
||||
refBean.setMonth(Month.APRIL);
|
||||
@@ -161,8 +186,10 @@ public class TestNewTypes extends BaseTestCase {
|
||||
refBean.setZoneId(ZoneId.systemDefault());
|
||||
refBean.setZoneOffset(ZonedDateTime.now().getOffset());
|
||||
refBean.setYearMonth(YearMonth.of(2014, 9));
|
||||
refBean.setMonthDay(MonthDay.of( 9, 22));
|
||||
refBean.setPath(Paths.get(TEMP_PATH));
|
||||
refBean.setPeriod(Period.of(4,3,2));
|
||||
refBean.setDuration(Duration.ofMinutes(5));
|
||||
|
||||
testSetGetPath(refBean);
|
||||
}
|
||||
@@ -179,6 +206,7 @@ public class TestNewTypes extends BaseTestCase {
|
||||
ExpressionPath localDateTime = beanType.getExpressionPath("localDateTime");
|
||||
ExpressionPath offsetDateTime = beanType.getExpressionPath("offsetDateTime");
|
||||
ExpressionPath zonedDateTime = beanType.getExpressionPath("zonedDateTime");
|
||||
ExpressionPath localTime = beanType.getExpressionPath("localTime");
|
||||
ExpressionPath instant = beanType.getExpressionPath("instant");
|
||||
ExpressionPath year = beanType.getExpressionPath("year");
|
||||
ExpressionPath month = beanType.getExpressionPath("month");
|
||||
@@ -186,8 +214,10 @@ public class TestNewTypes extends BaseTestCase {
|
||||
ExpressionPath zoneId = beanType.getExpressionPath("zoneId");
|
||||
ExpressionPath zoneOffset = beanType.getExpressionPath("zoneOffset");
|
||||
ExpressionPath yearMonth = beanType.getExpressionPath("yearMonth");
|
||||
ExpressionPath monthDay = beanType.getExpressionPath("monthDay");
|
||||
ExpressionPath path = beanType.getExpressionPath("path");
|
||||
ExpressionPath period = beanType.getExpressionPath("period");
|
||||
ExpressionPath duration = beanType.getExpressionPath("duration");
|
||||
|
||||
localDate.pathSet(testBean, refBean.getLocalDate());
|
||||
assertThat(localDate.pathGet(testBean)).isEqualTo(refBean.getLocalDate());
|
||||
@@ -201,6 +231,9 @@ public class TestNewTypes extends BaseTestCase {
|
||||
zonedDateTime.pathSet(testBean, refBean.getZonedDateTime());
|
||||
assertThat(zonedDateTime.pathGet(testBean)).isEqualTo(refBean.getZonedDateTime());
|
||||
|
||||
localTime.pathSet(testBean, refBean.getLocalTime());
|
||||
assertThat(localTime.pathGet(testBean)).isEqualTo(refBean.getLocalTime());
|
||||
|
||||
instant.pathSet(testBean, refBean.getInstant());
|
||||
assertThat(instant.pathGet(testBean)).isEqualTo(refBean.getInstant());
|
||||
|
||||
@@ -222,12 +255,18 @@ public class TestNewTypes extends BaseTestCase {
|
||||
yearMonth.pathSet(testBean, refBean.getYearMonth());
|
||||
assertThat(yearMonth.pathGet(testBean)).isEqualTo(refBean.getYearMonth());
|
||||
|
||||
monthDay.pathSet(testBean, refBean.getMonthDay());
|
||||
assertThat(monthDay.pathGet(testBean)).isEqualTo(refBean.getMonthDay());
|
||||
|
||||
path.pathSet(testBean, refBean.getPath());
|
||||
assertThat(path.pathGet(testBean)).isEqualTo(refBean.getPath());
|
||||
|
||||
period.pathSet(testBean, refBean.getPeriod());
|
||||
assertThat(period.pathGet(testBean)).isEqualTo(refBean.getPeriod());
|
||||
|
||||
duration.pathSet(testBean, refBean.getDuration());
|
||||
assertThat(duration.pathGet(testBean)).isEqualTo(refBean.getDuration());
|
||||
|
||||
Ebean.save(refBean);
|
||||
Ebean.save(testBean);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import io.ebean.BaseTestCase;
|
||||
import io.ebean.OrderBy;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test the OrderBy object and especially its parsing.
|
||||
@@ -153,4 +156,92 @@ public class TestOrderByParse extends BaseTestCase {
|
||||
assertEquals("id, name", copy.toStringFormat());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingWithCollation() {
|
||||
|
||||
OrderBy<Object> o1 = new OrderBy<>();
|
||||
o1.asc("id", "latin_1");
|
||||
assertTrue(o1.getProperties().size() == 1);
|
||||
assertTrue(o1.getProperties().get(0).getProperty().equals("id"));
|
||||
assertTrue(o1.getProperties().get(0).isAscending());
|
||||
assertEquals("id collate latin_1", o1.toStringFormat());
|
||||
|
||||
o1 = new OrderBy<>();
|
||||
o1.desc("id", "latin_1");
|
||||
assertTrue(o1.getProperties().size() == 1);
|
||||
assertTrue(o1.getProperties().get(0).getProperty().equals("id"));
|
||||
assertTrue(!o1.getProperties().get(0).isAscending());
|
||||
assertEquals("id collate latin_1 desc", o1.toStringFormat());
|
||||
|
||||
o1 = new OrderBy<>();
|
||||
o1.desc("id", "latin_1");
|
||||
o1.asc("date");
|
||||
assertTrue(o1.getProperties().size() == 2);
|
||||
assertTrue(o1.getProperties().get(0).getProperty().equals("id"));
|
||||
assertTrue(o1.getProperties().get(1).getProperty().equals("date"));
|
||||
assertTrue(!o1.getProperties().get(0).isAscending());
|
||||
assertTrue(o1.getProperties().get(1).isAscending());
|
||||
assertEquals("id collate latin_1 desc, date", o1.toStringFormat());
|
||||
|
||||
o1 = new OrderBy<>();
|
||||
o1.desc("id", "latin_1");
|
||||
o1.asc("name", "latin_2");
|
||||
assertTrue(o1.getProperties().size() == 2);
|
||||
assertTrue(o1.getProperties().get(0).getProperty().equals("id"));
|
||||
assertTrue(o1.getProperties().get(1).getProperty().equals("name"));
|
||||
assertTrue(!o1.getProperties().get(0).isAscending());
|
||||
assertTrue(o1.getProperties().get(1).isAscending());
|
||||
assertEquals("id collate latin_1 desc, name collate latin_2", o1.toStringFormat());
|
||||
|
||||
// functional (DB2) syntax
|
||||
o1 = new OrderBy<>();
|
||||
o1.desc("id", "COLLATION_KEY(${}, 'latin_1')");
|
||||
assertTrue(o1.getProperties().size() == 1);
|
||||
assertTrue(o1.getProperties().get(0).getProperty().equals("id"));
|
||||
assertTrue(!o1.getProperties().get(0).isAscending());
|
||||
assertEquals("COLLATION_KEY(id, 'latin_1') desc", o1.toStringFormat());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_with_nulls() {
|
||||
|
||||
OrderBy<Object> o1 = new OrderBy<>("id desc nulls high");
|
||||
OrderBy<Object> o2 = new OrderBy<>("id desc nulls high");
|
||||
OrderBy<Object> o3 = new OrderBy<>();
|
||||
o3.add("id desc nulls high");
|
||||
|
||||
assertEquals(o1, o2);
|
||||
assertEquals(o1, o3);
|
||||
|
||||
|
||||
OrderBy<Object> o4 = new OrderBy<>("id desc");
|
||||
OrderBy<Object> o5 = new OrderBy<>("oid desc nulls high");
|
||||
OrderBy<Object> o6 = new OrderBy<>("id desc nulls low");
|
||||
|
||||
assertNotEquals(o1, o4);
|
||||
assertNotEquals(o1, o5);
|
||||
assertNotEquals(o1, o6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_with_collation() {
|
||||
|
||||
OrderBy<Object> o1 = new OrderBy<>();
|
||||
o1.asc("name", "latin_1");
|
||||
|
||||
OrderBy<Object> o2 = new OrderBy<>();
|
||||
o2.asc("name", null);
|
||||
|
||||
OrderBy<Object> o3 = new OrderBy<>();
|
||||
o2.asc("name", "bar");
|
||||
|
||||
assertNotEquals(o1, o2);
|
||||
assertNotEquals(o1, o3);
|
||||
|
||||
OrderBy<Object> o4 = new OrderBy<>();
|
||||
o4.asc("name", "latin_1");
|
||||
assertEquals(o1, o4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
DROP PROCEDURE IF EXISTS usp_ebean_drop_foreign_keys;
|
||||
|
||||
delimiter $$
|
||||
------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN
|
||||
-- deletes all constraints and foreign keys referring to TABLE.COLUMN
|
||||
------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE PROCEDURE usp_ebean_drop_foreign_keys(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT FALSE;
|
||||
DECLARE c_fk_name CHAR(255);
|
||||
DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE
|
||||
DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = DATABASE() and TABLE_NAME = p_table_name and COLUMN_NAME = p_column_name
|
||||
AND REFERENCED_TABLE_NAME IS NOT NULL;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
||||
|
||||
OPEN curs;
|
||||
|
||||
|
||||
read_loop: LOOP
|
||||
FETCH curs INTO c_fk_name;
|
||||
IF done THEN
|
||||
@@ -26,7 +26,7 @@ BEGIN
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
END LOOP;
|
||||
|
||||
|
||||
CLOSE curs;
|
||||
END
|
||||
$$
|
||||
@@ -34,10 +34,10 @@ $$
|
||||
DROP PROCEDURE IF EXISTS usp_ebean_drop_column;
|
||||
|
||||
delimiter $$
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
|
||||
-- deletes the column and ensures that all indices and constraints are dropped first
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE PROCEDURE usp_ebean_drop_column(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255))
|
||||
BEGIN
|
||||
CALL usp_ebean_drop_foreign_keys(p_table_name, p_column_name);
|
||||
|
||||
@@ -10,16 +10,16 @@ if not exists (select name from sys.types where name = 'ebean_uniqueidentifier_
|
||||
if not exists (select name from sys.types where name = 'ebean_nvarchar_tvp') create type ebean_nvarchar_tvp as table (c1 nvarchar(max));
|
||||
|
||||
delimiter $$
|
||||
-----------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_indices TABLE, COLUMN
|
||||
-- deletes all indices referring to TABLE.COLUMN
|
||||
-----------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_indices @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
declare @indexName nvarchar(255)
|
||||
BEGIN
|
||||
DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i
|
||||
DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i
|
||||
join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id
|
||||
join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id
|
||||
where i.object_id = OBJECT_ID(@tableName) AND c.name = @columnName;
|
||||
@@ -38,10 +38,10 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_default_constraint TABLE, COLUMN
|
||||
-- deletes the default constraint, which has a random name
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_default_constraint @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @tmp nvarchar(1000)
|
||||
@@ -55,16 +55,16 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_constraints TABLE, COLUMN
|
||||
-- deletes constraints and foreign keys refering to TABLE.COLUMN
|
||||
--------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_constraints @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
declare @constraintName nvarchar(255)
|
||||
BEGIN
|
||||
DECLARE name_cursor CURSOR FOR
|
||||
DECLARE name_cursor CURSOR FOR
|
||||
SELECT cc.name from sys.check_constraints cc
|
||||
join sys.columns c on c.object_id = cc.parent_object_id and c.column_id = cc.parent_column_id
|
||||
where parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName
|
||||
@@ -89,10 +89,10 @@ END
|
||||
$$
|
||||
|
||||
delimiter $$
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN
|
||||
-- deletes the column annd ensures that all indices and constraints are dropped first
|
||||
-------------------------------------------------------------------------------------
|
||||
--
|
||||
CREATE OR ALTER PROCEDURE usp_ebean_drop_column @tableName nvarchar(255), @columnName nvarchar(255)
|
||||
AS SET NOCOUNT ON
|
||||
declare @sql nvarchar(1000)
|
||||
|
||||
Reference in New Issue
Block a user