mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-11-14 06:45:21 +00:00
Merge remote-tracking branch 'upstream/master' into ebean-new
# Conflicts: # ebean-api/pom.xml # ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java # ebean-autotune/pom.xml # ebean-bom/pom.xml # ebean-core-type/pom.xml # ebean-core/pom.xml # ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java # ebean-ddl-generator/pom.xml # ebean-externalmapping-api/pom.xml # ebean-externalmapping-xml/pom.xml # ebean-postgis/pom.xml # ebean-querybean/pom.xml # ebean-redis/pom.xml # ebean-test/pom.xml # ebean-test/src/test/resources/ebean.properties # ebean-test/testconfig/ebean-mariadb-10.3.properties # ebean-test/testconfig/ebean-mariadb.properties # ebean-test/testconfig/ebean-mysql.properties # ebean-test/testconfig/ebean-sqlserver17.properties # ebean/pom.xml # kotlin-querybean-generator/pom.xml # pom.xml # querybean-generator/pom.xml
This commit is contained in:
commit
6b0d04547e
96 files changed
+3220
-190
No files matched your search
@@ -223,6 +223,15 @@ public final class BindParams implements Serializable {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a named In parameter that is multi-valued.
|
||||
*/
|
||||
public Param setArrayParameter(String name, Collection<?> value) {
|
||||
Param p = getParam(name);
|
||||
p.setInValue(new MultiValueWrapper(value));
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an encryption key as a bind value.
|
||||
* <p>
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.ebeaninternal.server.querydefn.OrmUpdateProperties;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -399,6 +400,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
|
||||
|
||||
List<String> getSoftDeletePredicates();
|
||||
|
||||
/**
|
||||
* Bind the named multi-value array parameter which we would use with Postgres ANY.
|
||||
*/
|
||||
void setArrayParameter(String name, Collection<?> values);
|
||||
|
||||
/**
|
||||
* Return a copy of the query.
|
||||
*/
|
||||
|
||||
@@ -331,6 +331,12 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlUpdate setArrayParameter(String name, Collection<?> values) {
|
||||
bindParams.setArrayParameter(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlUpdate setNull(String name, int jdbcType) {
|
||||
bindParams.setNullParameter(name, jdbcType);
|
||||
|
||||
@@ -217,6 +217,11 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return beanDescriptor.docStoreMode(type, txnMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCascade() {
|
||||
return Flags.isRecurse(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the draftDirty property should be set to true for this request.
|
||||
*/
|
||||
|
||||
@@ -208,6 +208,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
||||
private final EntityBean prototypeEntityBean;
|
||||
|
||||
private final IdBinder idBinder;
|
||||
private final String idSelect;
|
||||
private String idBinderInLHSSql;
|
||||
private String idBinderIdSql;
|
||||
private String deleteByIdSql;
|
||||
@@ -349,6 +350,23 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
||||
propertiesIndex[i] = propMap.get(ebi.getProperty(i));
|
||||
}
|
||||
}
|
||||
idSelect = initIdSelect();
|
||||
}
|
||||
|
||||
String initIdSelect() {
|
||||
if (idProperty != null && !idProperty.name().equals("_idClass")) {
|
||||
return idProperty.name();
|
||||
} else if (entityType == EntityType.EMBEDDED) {
|
||||
return null;
|
||||
} else {
|
||||
StringJoiner sj = new StringJoiner(",");
|
||||
for (BeanProperty prop : propertiesNonMany) {
|
||||
if (prop.isImportedPrimaryKey()) {
|
||||
sj.add(prop.name());
|
||||
}
|
||||
}
|
||||
return sj.toString().intern();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isJacksonCorePresent() {
|
||||
@@ -3011,6 +3029,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
public String idSelect() {
|
||||
return idSelect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean should be inserted rather than updated.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,11 @@ abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
|
||||
this.elementHelp = elementHelp;
|
||||
}
|
||||
|
||||
@Override
|
||||
String initIdSelect() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String shortName(String name) {
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (pos > 1) {
|
||||
|
||||
@@ -35,8 +35,7 @@ public final class ImportedIdEmbedded implements ImportedId {
|
||||
BeanProperty[] embeddedProps = foreignAssocOne.properties();
|
||||
for (int i = 0; i < imported.length; i++) {
|
||||
String n = name + "." + foreignAssocOne.name() + "." + embeddedProps[i].name();
|
||||
BeanFkeyProperty fkey = new BeanFkeyProperty(n, imported[i].localDbColumn, foreignAssocOne.deployOrder());
|
||||
owner.descriptor().add(fkey);
|
||||
owner.descriptor().add(new BeanFkeyProperty(n, imported[i].localDbColumn, foreignAssocOne.deployOrder()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,8 +88,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
|
||||
|
||||
@Override
|
||||
public void addFkeys(String name) {
|
||||
BeanFkeyProperty fkey = new BeanFkeyProperty(name + "." + foreignProperty.name(), localDbColumn, owner.deployOrder());
|
||||
owner.descriptor().add(fkey);
|
||||
owner.descriptor().add(new BeanFkeyProperty(name + "." + foreignProperty.name(), localDbColumn, owner.deployOrder()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-1
@@ -5,7 +5,6 @@ import io.ebean.annotation.*;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.api.CoreLog;
|
||||
import io.ebeaninternal.server.deploy.DetermineManyType;
|
||||
import io.ebeaninternal.server.deploy.ManyType;
|
||||
import io.ebeaninternal.server.deploy.meta.*;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
@@ -174,7 +174,7 @@ public final class DeployUtil {
|
||||
*/
|
||||
void setDbArray(DeployBeanProperty prop, DbArray dbArray) {
|
||||
Class<?> type = prop.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, dbArray, prop.getGenericType(), prop.isNullable());
|
||||
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, prop.getGenericType(), prop.isNullable());
|
||||
if (scalarType == null) {
|
||||
throw new RuntimeException("No ScalarType for @DbArray type for [" + prop.getFullBeanName() + "]");
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,4 +1,6 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebeaninternal.server.deploy.ManyType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -7,9 +9,9 @@ import java.util.Set;
|
||||
/**
|
||||
* Determine the Many Type for a property.
|
||||
*/
|
||||
public final class DetermineManyType {
|
||||
final class DetermineManyType {
|
||||
|
||||
public ManyType getManyType(Class<?> type) {
|
||||
ManyType getManyType(Class<?> type) {
|
||||
if (type.equals(List.class)) {
|
||||
return ManyType.LIST;
|
||||
}
|
||||
@@ -37,8 +37,7 @@ final class DtoMetaBuilder {
|
||||
if (includeMethod(method)) {
|
||||
try {
|
||||
final String name = propertyName(method.getName());
|
||||
final Class<?> propertyType = propertyType(method);
|
||||
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name, propertyType));
|
||||
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name));
|
||||
} catch (Exception e) {
|
||||
CoreLog.log.debug("exclude on " + dtoType + " method " + method, e);
|
||||
}
|
||||
@@ -46,10 +45,6 @@ final class DtoMetaBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
static Class<?> propertyType(Method method) {
|
||||
return method.getParameterTypes()[0];
|
||||
}
|
||||
|
||||
static String propertyName(String methodName) {
|
||||
final String name = methodName.substring(3);
|
||||
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.SQLException;
|
||||
|
||||
final class DtoMetaProperty implements DtoReadSet {
|
||||
@@ -19,18 +20,30 @@ final class DtoMetaProperty implements DtoReadSet {
|
||||
private final MethodHandle setter;
|
||||
private final ScalarType<?> scalarType;
|
||||
|
||||
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name, Class<?> propertyType) throws IllegalAccessException, NoSuchMethodException {
|
||||
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name) throws IllegalAccessException, NoSuchMethodException {
|
||||
this.dtoType = dtoType;
|
||||
this.name = name;
|
||||
if (writeMethod != null) {
|
||||
this.setter = LOOKUP.findVirtual(dtoType, writeMethod.getName(), MethodType.methodType(void.class, propertyType));
|
||||
this.scalarType = typeManager.getScalarType(propertyType);
|
||||
this.setter = lookupMethodHandle(dtoType, writeMethod);
|
||||
this.scalarType = typeManager.getScalarType(propertyType(writeMethod), propertyClass(writeMethod));
|
||||
} else {
|
||||
this.scalarType = null;
|
||||
this.setter = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle lookupMethodHandle(Class<?> dtoType, Method method) throws NoSuchMethodException, IllegalAccessException {
|
||||
return LOOKUP.findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
|
||||
}
|
||||
|
||||
static Type propertyType(Method method) {
|
||||
return method.getParameters()[0].getParameterizedType();
|
||||
}
|
||||
|
||||
static Class<?> propertyClass(Method method) {
|
||||
return method.getParameterTypes()[0];
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
@@ -148,6 +149,16 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DtoQuery<T> setArrayParameter(String paramName, Collection<?> values) {
|
||||
if (ormQuery != null) {
|
||||
ormQuery.setArrayParameter(paramName, values);
|
||||
} else {
|
||||
bindParams.setArrayParameter(paramName, values);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DtoQuery<T> setParameters(Object... values) {
|
||||
if (ormQuery != null) {
|
||||
|
||||
@@ -586,9 +586,9 @@ public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<
|
||||
*/
|
||||
@Override
|
||||
public void setSelectId() {
|
||||
// clear select and fetch joins..
|
||||
// clear select and fetch joins
|
||||
detail.clear();
|
||||
select(beanDescriptor.idBinder().getIdProperty());
|
||||
select(beanDescriptor.idSelect());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1586,6 +1586,17 @@ public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArrayParameter(String name, Collection<?> values) {
|
||||
if (namedParams != null) {
|
||||
throw new IllegalStateException("setArrayParameter() not supported when EQL parsed query");
|
||||
}
|
||||
if (bindParams == null) {
|
||||
bindParams = new BindParams();
|
||||
}
|
||||
bindParams.setArrayParameter(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkPagingOrderBy() {
|
||||
return orderById && !useDocStore;
|
||||
|
||||
@@ -289,6 +289,18 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return nativeMap.get(jdbcType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getScalarType(Type propertyType, Class<?> propertyClass) {
|
||||
if (propertyType instanceof ParameterizedType) {
|
||||
ParameterizedType pt = (ParameterizedType)propertyType;
|
||||
Type rawType = pt.getRawType();
|
||||
if (List.class == rawType || Set.class == rawType) {
|
||||
return getArrayScalarType((Class<?>)rawType, propertyType, true);
|
||||
}
|
||||
}
|
||||
return getScalarType(propertyClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* This can return null if no matching ScalarType is found.
|
||||
*/
|
||||
@@ -327,7 +339,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getArrayScalarType(Class<?> type, DbArray dbArray, Type genericType, boolean nullable) {
|
||||
public ScalarType<?> getArrayScalarType(Class<?> type, Type genericType, boolean nullable) {
|
||||
Type valueType = getValueType(genericType);
|
||||
if (type.equals(List.class)) {
|
||||
return getArrayScalarTypeList(valueType, nullable);
|
||||
@@ -366,12 +378,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
Type genericType = prop.getGenericType();
|
||||
boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop);
|
||||
|
||||
boolean keepSource = prop.getMutationDetection() == MutationDetection.SOURCE
|
||||
|| (prop.getMutationDetection() == MutationDetection.DEFAULT && defaultJsonMutationDetection == MutationDetection.SOURCE);
|
||||
if (type.equals(List.class)) {
|
||||
DocPropertyType docType = getDocType(genericType);
|
||||
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
|
||||
return ScalarTypeJsonList.typeFor(postgres, dbType, docType, prop.isNullable(), keepSource);
|
||||
return ScalarTypeJsonList.typeFor(postgres, dbType, docType, prop.isNullable(), jsonManager.keepSource(prop));
|
||||
} else {
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
@@ -379,14 +389,14 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
if (type.equals(Set.class)) {
|
||||
DocPropertyType docType = getDocType(genericType);
|
||||
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
|
||||
return ScalarTypeJsonSet.typeFor(postgres, dbType, docType, prop.isNullable(), keepSource);
|
||||
return ScalarTypeJsonSet.typeFor(postgres, dbType, docType, prop.isNullable(), jsonManager.keepSource(prop));
|
||||
} else {
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
}
|
||||
if (type.equals(Map.class)) {
|
||||
if (!hasJacksonAnnotations && isMapValueTypeObject(genericType)) {
|
||||
return ScalarTypeJsonMap.typeFor(postgres, dbType, keepSource);
|
||||
return ScalarTypeJsonMap.typeFor(postgres, dbType, jsonManager.keepSource(prop));
|
||||
} else {
|
||||
return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,13 @@ final class JsonTrim {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = json.charAt(i);
|
||||
if (c == '\"') {
|
||||
if (!escaped) quoted = !quoted;
|
||||
else escaped = false;
|
||||
if (!escaped) {
|
||||
quoted = !quoted;
|
||||
} else {
|
||||
escaped = false;
|
||||
}
|
||||
} else if (escaped) {
|
||||
escaped = false;
|
||||
} else if (quoted && c == '\\') {
|
||||
escaped = true;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.ebean.ModifyAwareType;
|
||||
import io.ebean.annotation.MutationDetection;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
final class TypeJsonManager {
|
||||
|
||||
@@ -25,6 +26,17 @@ final class TypeJsonManager {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
boolean keepSource(DeployBeanProperty prop) {
|
||||
if (prop.getMutationDetection() == MutationDetection.SOURCE) {
|
||||
return true;
|
||||
} else if (prop.getMutationDetection() == MutationDetection.DEFAULT) {
|
||||
prop.setMutationDetection(mutationDetection);
|
||||
return mutationDetection == MutationDetection.SOURCE;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String postgresType(int dbType) {
|
||||
if (postgres) {
|
||||
switch (dbType) {
|
||||
|
||||
@@ -47,6 +47,13 @@ public interface TypeManager {
|
||||
*/
|
||||
ScalarType<?> getScalarType(Class<?> type, int jdbcType);
|
||||
|
||||
/**
|
||||
* Find and return the ScalarType taking into account the property type with generics.
|
||||
* <p>
|
||||
* For example Array based ScalarType for types like {@code List<String>}.
|
||||
*/
|
||||
ScalarType<?> getScalarType(Type propertyType, Class<?> type);
|
||||
|
||||
/**
|
||||
* Create a ScalarType for an Enum using a mapping (rather than JPA Ordinal
|
||||
* or String which has limitations).
|
||||
@@ -64,7 +71,7 @@ public interface TypeManager {
|
||||
/**
|
||||
* Return the ScalarType used to handle DB ARRAY.
|
||||
*/
|
||||
ScalarType<?> getArrayScalarType(Class<?> type, DbArray dbArray, Type genericType, boolean nullable);
|
||||
ScalarType<?> getArrayScalarType(Class<?> type, Type genericType, boolean nullable);
|
||||
|
||||
/**
|
||||
* Return the ScalarType used to handle HSTORE (Map<String,String>).
|
||||
|
||||
Reference in new issue
Block a user