Compare commits

...
Author SHA1 Message Date
Rob Bygrave 09115a824d [maven-release-plugin] prepare release ebean-parent-12.13.1 2021-11-26 21:57:04 +13:00
Rob Bygrave 28d4d07966 test config only, stop dumping metrics on jvm shutdown 2021-11-26 21:52:40 +13:00
Rob Bygrave c3e91fed65 Tidy TestElementCollectionBasicSet only 2021-11-26 21:33:26 +13:00
Rob Bygrave 2cad98ad26 Move DetermineManyType into io.ebeaninternal.server.deploy.parse
This allows it to be package private
2021-11-26 21:25:54 +13:00
Rob Bygrave 8a25a7b6ec #2444 - exists and findCount queries produce NPE on entity defined with IdClass - SqlTreeProperties.add(SqlTreeProperties.java:38) 2021-11-26 21:10:31 +13:00
Rob Bygrave 83fbfd1b2a No effective change - tidy inline for ImportedIdEmbedded, ImportedIdSimple 2021-11-26 20:54:28 +13:00
Rob Bygrave a9c6cd15a1 #2433 - Postgres JSONB dirty checking - trim json 2021-11-26 16:39:09 +13:00
Rob Bygrave 63b9b42dc8 #2433 - Postgres JSONB dirty checking - trim json 2021-11-26 16:34:15 +13:00
Rob Bygrave 268146df85 Tidy up TypeManager API after #2435 2021-11-26 14:55:16 +13:00
Rob Bygrave d05a77e755 reset test datasource back to h2 2021-11-26 14:48:45 +13:00
Rob Bygrave 69c768b3be Merge branch 'majkiw-master' 2021-11-26 14:46:42 +13:00
Rob Bygrave 07f9bf98c3 #2436 - SQL Update doesn't handle named parameters for array types in Postgres 2021-11-26 14:46:06 +13:00
Rob Bygrave 9af64f61f7 #2435 - Fix DBArray is not loaded in asDto Postgres queries 2021-11-26 14:32:47 +13:00
Rob Bygrave c1a78d3c8b Merge branch 'master' of https://github.com/majkiw/ebean into majkiw-master 2021-11-25 18:53:28 +13:00
Rob Bygrave 08fc7399ec Tidy DefaultTypeManager with enhanced for 2021-11-25 18:30:00 +13:00
Rob Bygrave 86d805c9fa Tidy internals only for OrmQueryRequest after merge of #2442 2021-11-22 15:21:03 +13:00
Rob BygraveandGitHub 34135360ed Merge pull request #2442 from FOCONIS/findmap-with-beancache-without-mapkey
findMap() with beanCache should use idPoperty if mapKey = null
2021-11-22 15:15:07 +13:00
Rob Bygrave 53b4d6fd73 Merge branch 'FOCONIS-assume-infoInherit-infoType-without-children' 2021-11-22 15:12:29 +13:00
Rob Bygrave 1114ccfb3a #2441 Flatten and re-order if block in AssocOneHelpRefInherit when determining BeanDescriptor 2021-11-22 15:12:18 +13:00
Rob Bygrave b4403c58d1 Merge branch 'assume-infoInherit-infoType-without-children' of https://github.com/FOCONIS/ebean into FOCONIS-assume-infoInherit-infoType-without-children 2021-11-22 15:06:34 +13:00
Rob Bygrave 951903db76 Merge branch 'FOCONIS-json-deserialize-references' 2021-11-22 15:00:14 +13:00
Rob Bygrave 093d111524 #2440 - Re-use existing referenceIdPropertyOnly() method 2021-11-22 14:59:40 +13:00
Rob Bygrave 08e166a9b7 Merge branch 'json-deserialize-references' of https://github.com/FOCONIS/ebean into FOCONIS-json-deserialize-references 2021-11-22 14:51:21 +13:00
Rob Bygrave d5fe7a9ebe Whitespace format only - OrmQueryPropertiesParser 2021-11-22 10:23:27 +13:00
Rob BygraveandGitHub 9f52856343 Merge pull request #2439 from FOCONIS/path-properties-query-with-all-props
Path properties query with all props
2021-11-22 09:15:08 +13:00
Rob BygraveandGitHub 0b529603c4 Merge pull request #2438 from FOCONIS/type-get-all-for-repeated-annotations
FIX: typeGetAll did not work with repeated annotations on one class
2021-11-22 09:01:06 +13:00
Noemi Szemenyei 60d0a3da39 findMap() with beanCache should use idPoperty if mapKey = null 2021-11-19 11:53:37 +01:00
Noemi Szemenyei 1c224444c0 Assume InfoInherit infoType when it has no children 2021-11-16 13:44:53 +01:00
Jonas PöhlerandNoemi Szemenyei d3e07defa0 FIX: Json deserialize references 2021-11-16 11:57:30 +01:00
Noemi Szemenyei 1b5d379ed3 Fix for Query with PathProperties (*,x(y)) 2021-11-16 11:45:18 +01:00
Noemi Szemenyei b90393a691 Unittest for select Query with (*,x(y)) 2021-11-16 11:39:14 +01:00
Jonas PöhlerandNoemi Szemenyei 2d26740286 FIX: typeGetAll did not work with repeated annotations on one class 2021-11-16 11:24:22 +01:00
Rob Bygrave 5807874c9e [maven-release-plugin] prepare for next development iteration 2021-11-04 11:19:32 +13:00
Rob Bygrave ea7b4e8162 [maven-release-plugin] prepare release ebean-parent-12.13.0 2021-11-04 11:19:25 +13:00
Rob Bygrave 43742fdc0b Bump version to 12.13.0-SNAPSHOT 2021-11-04 11:16:50 +13:00
Rob Bygrave 8ef71bd451 Bump version to 12.13.0-SNAPSHOT 2021-11-04 11:02:45 +13:00
Rob Bygrave 0f60e2240c Bump version to 12.13.0-SNAPSHOT 2021-11-04 10:57:48 +13:00
Rob Bygrave 2cbb161ed5 Follow up to #2437 - Rename internal "dead/alive" to "replaced" 2021-11-04 10:40:04 +13:00
Rob BygraveandGitHub a47caec85b Merge pull request #2437 from FOCONIS/fix-persistence-context
FIX: Subsequent findEach / findList does not work reliable [Fixes regression in 12.3.3]
2021-11-04 09:59:31 +13:00
Roland Praml fd1b5f58bc FIX: Subsequent findEach / findList does not work reliable (Regression of #2411) 2021-11-03 11:34:04 +01:00
Michal Wysocki 39a4035f3b Extra assertions for DBArray in asDTO and sqlUpdate 2021-11-02 13:25:42 +01:00
Rob Bygrave 0bb7d79015 Tidy build.yml 2021-10-28 22:40:10 +13:00
Rob BygraveandGitHub 9907cffe6e Update README.md 2021-10-28 22:38:48 +13:00
Rob Bygrave 704a138ff0 Tidy build.yml and TestExtraScalarTypes 2021-10-28 22:34:55 +13:00
Rob Bygrave f3cab4ee10 Merge branch 'master' of github.com:ebean-orm/ebean 2021-10-28 22:33:48 +13:00
Rob Bygrave d507452d63 Fix test TestExtraScalarTypes for github workflows build 2021-10-28 22:33:28 +13:00
Rob BygraveandGitHub 893aa6cb1a Update build.yml 2021-10-28 22:26:13 +13:00
Rob BygraveandGitHub e92fd2ef06 Add github workflows build.yml 2021-10-28 22:19:24 +13:00
Rob BygraveandGitHub bdad8b258a Merge pull request #2427 from FOCONIS/bug-reload-fails-on-partial-beans
FIX: When a bean is modified in persistence context and searched again, it will loose the change
2021-10-22 16:17:31 +13:00
Rob Bygrave a6cdf8d6dc Turn off nexus.staging.autoReleaseAfterClose 2021-10-22 10:52:16 +13:00
Rob Bygrave e232c724c0 maven.deploy.skip test modules and fix agent versions 2021-10-22 10:49:57 +13:00
Roland Praml d55023dbc7 FIX: When a bean is modified in persistence context and searched again, it will loose the change 2021-10-21 16:50:53 +02:00
Rob Bygrave fa4e013692 [maven-release-plugin] prepare for next development iteration 2021-10-21 21:36:29 +13:00
63 changed files with 718 additions and 181 deletions
+36
View File
@@ -0,0 +1,36 @@
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [8]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn package
+1 -1
View File
@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/ebean-orm/ebean.svg?branch=master)](https://travis-ci.org/ebean-orm/ebean)
[![Build](https://github.com/ebean-orm/ebean/actions/workflows/build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/build.yml)
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
# Sponsors
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean api</name>
@@ -2,6 +2,8 @@ package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -127,6 +129,13 @@ public interface DtoQuery<T> extends CancelableQuery {
*/
DtoQuery<T> setParameter(String name, Object value);
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
* <p>
* For Postgres this binds an ARRAY rather than expands into multiple bind values.
*/
DtoQuery<T> setArrayParameter(String name, Collection<?> values);
/**
* Bind the parameter by its index position (1 based like JDBC).
*/
@@ -1,5 +1,7 @@
package io.ebean;
import java.util.Collection;
/**
* A SqlUpdate for executing insert update or delete statements.
* <p>
@@ -324,6 +326,13 @@ public interface SqlUpdate {
*/
SqlUpdate setParameter(String name, Object param);
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
* <p>
* For Postgres this binds an ARRAY rather than expands into multiple bind values.
*/
SqlUpdate setArrayParameter(String name, Collection<?> values);
/**
* Set a named parameter that has a null value. Exactly the same as
* {@link #setNullParameter(String, int)}.
@@ -2,6 +2,7 @@ package io.ebean.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -57,10 +58,8 @@ public class AnnotationUtil {
private static <A extends Annotation> void typeGetAllCollect(Class<?> clazz, Class<A> annotationType, Set<A> result) {
while (clazz != null && clazz != Object.class) {
final A val = clazz.getAnnotation(annotationType);
if (val != null) {
result.add(val);
}
final A[] annotations = clazz.getAnnotationsByType(annotationType);
Collections.addAll(result, annotations);
clazz = clazz.getSuperclass();
}
}
@@ -0,0 +1,28 @@
package io.ebean.util;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.util.Set;
import org.junit.jupiter.api.Test;
import io.ebean.annotation.Formula;
public class TestAnnotationUtil {
@Formula(select = "x")
@Formula(select = "y")
private static class TestObject {
}
@Test
public void testRepeatableAnnotation() {
Set<Formula> list = AnnotationUtil.typeGetAll(TestObject.class, Formula.class);
assertThat(list).hasSize(2);
}
}
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.3</tag>
<tag>ebean-parent-12.13.1</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
+5 -5
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.3</tag>
<tag>ebean-parent-12.13.1</tag>
</scm>
<dependencies>
@@ -41,19 +41,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
@@ -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);
@@ -36,7 +36,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
private final Boolean readOnly;
private LoadContext loadContext;
private PersistenceContext persistenceContext;
private JsonReadOptions jsonRead;
private HashQuery cacheKey;
private CQueryPlanKey queryPlanKey;
private SpiQuerySecondary secondaryQueries;
@@ -259,7 +258,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (query.getPersistenceContext() == null) {
query.setPersistenceContext(persistenceContext);
}
jsonRead = new JsonReadOptions();
JsonReadOptions jsonRead = new JsonReadOptions();
jsonRead.setPersistenceContext(persistenceContext);
if (!query.isDisableLazyLoading()) {
loadContext = new DLoadContext(this, secondaryQueries);
@@ -534,7 +533,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
@SuppressWarnings({"rawtypes"})
private void mergeCacheHitsToMap(BeanCollection<T> result) {
BeanMap map = (BeanMap)result;
BeanMap map = (BeanMap) result;
ElPropertyValue property = mapProperty();
for (T bean : cacheBeans) {
map.internalPut(property.pathGet(bean), bean);
@@ -562,17 +561,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
@SuppressWarnings("unchecked")
private <K> Map<K, T> cacheBeansToMap() {
ElPropertyValue property = mapProperty();
Map<K,T> map = new LinkedHashMap<>();
Map<K, T> map = new LinkedHashMap<>();
for (T bean : cacheBeans) {
map.put((K)property.pathGet(bean), bean);
map.put((K) property.pathGet(bean), bean);
}
return map;
}
private ElPropertyValue mapProperty() {
ElPropertyValue property = beanDescriptor.elGetValue(query.getMapKey());
final String key = query.getMapKey();
final ElPropertyValue property = key == null ? beanDescriptor.idProperty() : beanDescriptor.elGetValue(key);
if (property == null) {
throw new IllegalStateException("Unknown map key property " + query.getMapKey());
throw new IllegalStateException("Unknown map key property " + key);
}
return property;
}
@@ -634,7 +634,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (cached != null && isAuditReads() && readAuditQueryType()) {
if (cached instanceof BeanCollection) {
// raw sql can't use L2 cache so normal queries only in here
Collection<T> actualDetails = ((BeanCollection<T>)cached).getActualDetails();
Collection<T> actualDetails = ((BeanCollection<T>) cached).getActualDetails();
List<Object> ids = new ArrayList<>(actualDetails.size());
for (T bean : actualDetails) {
ids.add(beanDescriptor.idForJson(bean));
@@ -645,13 +645,13 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (Boolean.FALSE.equals(query.isReadOnly())) {
// return shallow copies if readonly is explicitly set to false
if (cached instanceof BeanCollection) {
cached = ((BeanCollection<?>)cached).getShallowCopy();
cached = ((BeanCollection<?>) cached).getShallowCopy();
} else if (cached instanceof List) {
cached = new CopyOnFirstWriteList<>((List<?>)cached);
cached = new CopyOnFirstWriteList<>((List<?>) cached);
} else if (cached instanceof Set) {
cached = new LinkedHashSet<>((Set<?>)cached);
cached = new LinkedHashSet<>((Set<?>) cached);
} else if (cached instanceof Map) {
cached = new LinkedHashMap<>((Map<?,?>)cached);
cached = new LinkedHashMap<>((Map<?, ?>) cached);
}
}
return cached;
@@ -31,7 +31,12 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
Object read(DbReadContext ctx) throws SQLException {
// read discriminator to determine the type
InheritInfo rowInheritInfo = inherit.readType(ctx);
if (rowInheritInfo == null) {
BeanDescriptor<?> desc;
if (rowInheritInfo != null) {
desc = rowInheritInfo.desc();
} else if (!inherit.hasChildren()) {
desc = inherit.desc();
} else {
// ignore the id property
property.targetIdBinder.loadIgnore(ctx);
return null;
@@ -42,7 +47,6 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
}
// check transaction context to see if it already exists
PersistenceContext pc = ctx.getPersistenceContext();
BeanDescriptor<?> desc = rowInheritInfo.desc();
Object existing = desc.contextGet(pc, id);
if (existing != null) {
return existing;
@@ -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.
*
@@ -3055,6 +3077,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return versionPropertyIndex > -1 && ebi.isLoadedProperty(versionPropertyIndex);
}
void setReferenceIfIdOnly(EntityBeanIntercept ebi) {
if (referenceIdPropertyOnly(ebi)) {
ebi.setReference(idPropertyIndex);
}
}
/**
* Set the version value returning it in primitive long form.
*/
@@ -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) {
@@ -152,6 +152,9 @@ final class BeanDescriptorJsonHelp<T> {
}
if (contextBean == null) {
readJson.beanVisitor(bean, unmappedProperties);
if (!isNullOrZero(id)) {
desc.setReferenceIfIdOnly(bean._ebean_getIntercept());
}
}
if (path != null) {
readJson.popPath();
@@ -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
@@ -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;
@@ -172,7 +172,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() + "]");
}
@@ -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;
}
@@ -268,9 +268,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (isLoadContextBeanNeeded(queryMode, contextBean)) {
// refresh it anyway (lazy loading for example)
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
@@ -683,14 +690,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
return "SqlTreeNodeBean: " + desc;
}
private boolean isLoadContextBeanNeeded(Mode queryMode, EntityBean contextBean) {
// if explicitly set loadContextBean to true, then reload
if (queryMode.isLoadContextBean()) {
return true;
}
// reload if contextBean is partial object
return !contextBean._ebean_getIntercept().isFullyLoadedBean();
}
@Override
public boolean hasMany() {
@@ -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;
@@ -37,7 +37,11 @@ final class OrmQueryPropertiesParser {
if (rawProperties.equals("*")) {
return ALL;
}
return new Response(false, splitRawSelect(rawProperties));
final Set<String> included = splitRawSelect(rawProperties);
if (included.contains("*")) {
return ALL;
}
return new Response(false, included);
}
/**
@@ -275,12 +275,18 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
return null;
}
private void put(Object id, Object b) {
private void put(Object id, Object bean) {
Object existing;
if (useReferences) {
weakCount++;
map.put(id, new BeanRef(this, id, b, queue));
existing = map.put(id, new BeanRef(this, id, bean, queue));
} else {
map.put(id, b);
existing = map.put(id, bean);
}
if (existing instanceof BeanRef) {
// when a BeanRef is replaced, its expunge() must NOT remove an entry
((BeanRef) existing).setReplaced();
weakCount--;
}
}
@@ -330,6 +336,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
private final ClassContext classContext;
private final Object key;
private boolean replaced;
private BeanRef(ClassContext classContext, Object key, Object referent, ReferenceQueue<? super Object> q) {
super(referent, q);
@@ -337,8 +344,14 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
this.key = key;
}
private void setReplaced() {
replaced = true;
}
private void expunge() {
classContext.remove(key);
if (!replaced) {
classContext.remove(key);
}
}
}
@@ -251,6 +251,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.
*/
@@ -286,7 +298,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);
@@ -591,8 +603,7 @@ public final class DefaultTypeManager implements TypeManager {
*/
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType, int length, boolean withConstraint) {
Map<String, String> nameValueMap = new LinkedHashMap<>();
Enum<?>[] enumConstants = enumType.getEnumConstants();
for (Enum<?> enumConstant : enumConstants) {
for (Enum<?> enumConstant : enumType.getEnumConstants()) {
try {
Object value = method.invoke(enumConstant);
nameValueMap.put(enumConstant.name(), value.toString());
@@ -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;
}
@@ -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>).
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean external mapping api</name>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.3</tag>
<tag>ebean-parent-12.13.1</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean postgis</name>
@@ -23,7 +23,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
@@ -74,7 +74,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
@@ -56,21 +56,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean test</name>
@@ -29,14 +29,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
@@ -208,19 +208,33 @@ public class DtoQueryTest extends BaseTestCase {
ResetBasicData.reset();
LoggedSql.start();
List<Integer> ids = Arrays.asList(1, 2);
List<DCust> list = server().findDto(DCust.class, "select id, name from o_customer where id = any(?)")
List<DCust> list = DB.findDto(DCust.class, "select id, name from o_customer where id = any(?)")
.setParameter(ids)
.findList();
assertThat(list).isNotEmpty();
list = server().findDto(DCust.class, "select id, name from o_customer where id in (:idList)")
List<DCust> list1 = DB.findDto(DCust.class, "select id, name from o_customer where id in (:idList)")
.setParameter("idList", ids)
.findList();
assertThat(list).isNotEmpty();
assertThat(list1).isNotEmpty();
List<DCust> list2 = DB.findDto(DCust.class, "select id, name from o_customer where id = any(:idList)")
.setArrayParameter("idList", ids)
.findList();
assertThat(list2).isNotEmpty();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(3);
assertThat(sql.get(0)).contains(" id = any(?)");
assertThat(sql.get(1)).contains(" id in (?,?)");
assertThat(sql.get(2)).contains(" id = any(?)");
}
@ForPlatform(Platform.POSTGRES)
@@ -1,8 +1,11 @@
package io.ebean.text;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.FetchPath;
import io.ebean.Query;
import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,7 +17,7 @@ import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
public class PathPropertiesTests {
public class PathPropertiesTests extends BaseTestCase {
private static final Logger log = LoggerFactory.getLogger(PathPropertiesTests.class);
@@ -212,4 +215,16 @@ public class PathPropertiesTests {
String asJson = DB.json().toJson(list, pathProps);
log.info("Json: {}", asJson);
}
@Test
public void test_withAllPropsQuery() {
PathProperties root = PathProperties.parse("*,billingAddress(line1)");
LoggedSql.start();
Query<Customer> query = DB.find(Customer.class).apply(root);
query.findList();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.name, t0.smallnote, t0.anniversary, t0.cretime, t0.updtime, t0.version, t0.shipping_address_id, t1.id, t1.line_1 from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id;");
}
}
@@ -34,8 +34,10 @@ public class DtoMetaBuilderTest {
Map<String, Method> methods = getIncludedMethodsFor(D0.class);
assertThat(methods).hasSize(2);
assertThat(DtoMetaBuilder.propertyType(methods.get("setName"))).isEqualTo(String.class);
assertThat(DtoMetaBuilder.propertyType(methods.get("setId"))).isEqualTo(long.class);
assertThat(DtoMetaProperty.propertyClass(methods.get("setName"))).isEqualTo(String.class);
assertThat(DtoMetaProperty.propertyClass(methods.get("setId"))).isEqualTo(long.class);
assertThat(DtoMetaProperty.propertyType(methods.get("setName"))).isEqualTo(String.class);
assertThat(DtoMetaProperty.propertyType(methods.get("setId"))).isEqualTo(long.class);
}
@Test
@@ -5,17 +5,59 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class JsonTrimTest {
class JsonTrimTest {
@Test
public void trim_array() {
void trim_array() {
final String trimmed = JsonTrim.trim("[{\"name\": \"one\", \"along\": 1, \"timestamp\": 1629609021559}, {\"name\": \"two\", \"along\": 2, \"timestamp\": 1629609021559}]");
assertThat(trimmed).isEqualTo("[{\"name\":\"one\",\"along\":1,\"timestamp\":1629609021559},{\"name\":\"two\",\"along\":2,\"timestamp\":1629609021559}]");
}
@Test
public void trim_object() {
void trim_object() {
final String trimmed = JsonTrim.trim("{\"name\": \"one\",\t \t \"along\": 1, \"timestamp\": 1629609021559}");
assertThat(trimmed).isEqualTo("{\"name\":\"one\",\"along\":1,\"timestamp\":1629609021559}");
}
@Test
void trim_object_embeddedEscapeSlash() {
final String trimmed = JsonTrim.trim("{\"a\": \"o\\nf\",\t \t \n \"b\": 1}");
assertThat(trimmed).isEqualTo("{\"a\":\"o\\nf\",\"b\":1}");
}
@Test
void trim_escapedTabNewLine() {
final String trimmed = JsonTrim.trim("{\"a\": \"o\\t\\nf\",\t \t \n \"b\": 1}");
assertThat(trimmed).isEqualTo("{\"a\":\"o\\t\\nf\",\"b\":1}");
}
@Test
void trim_leadingEscapedNewLine() {
final String trimmed = JsonTrim.trim("{\"a\": \"\\no\\t\\nf\\n\",\t \t \n \"b\": 1}");
assertThat(trimmed).isEqualTo("{\"a\":\"\\no\\t\\nf\\n\",\"b\":1}");
}
@Test
void trim_trailingEscapedNewLine() {
final String trimmed = JsonTrim.trim("{\"a\": \"o\\t\\nf\\n\",\t \t \n \"b\": 1}");
assertThat(trimmed).isEqualTo("{\"a\":\"o\\t\\nf\\n\",\"b\":1}");
}
@Test
void trim_trailingEscapedSlash() {
final String trimmed = JsonTrim.trim("{\"a\": \"o\\t\\nf\\\\\",\t \t \n \"b\": 1}");
assertThat(trimmed).isEqualTo("{\"a\":\"o\\t\\nf\\\\\",\"b\":1}");
}
@Test
void trim_object_embeddedEscaped() {
final String trimmed = JsonTrim.trim("{\"name\": \"one\nfoo\nbar\\bazz\tboo\",\t \t \n \"along\": 1}");
assertThat(trimmed).isEqualTo("{\"name\":\"one\nfoo\nbar\\bazz\tboo\",\"along\":1}");
}
@Test
void trim_escaped() {
final String trimmed = JsonTrim.trim(" \t \n {\"a\": \n \"\\t1\\t2\\n3\\\\\",\t \n \"b\": \"\\t1\\t2\\n3\\\\\" , \t \n \"c\": \"\\t1\\t2\\n3\\\\\" \t \n }");
assertThat(trimmed).isEqualTo("{\"a\":\"\\t1\\t2\\n3\\\\\",\"b\":\"\\t1\\t2\\n3\\\\\",\"c\":\"\\t1\\t2\\n3\\\\\"}");
}
}
@@ -2,12 +2,18 @@ package org.tests.basic;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Country;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestLoadBeanCache extends BaseTestCase {
@@ -31,4 +37,30 @@ public class TestLoadBeanCache extends BaseTestCase {
assertTrue(loadedNz == nz);
}
@Test
public void testLoadWithFindMap() {
ResetBasicData.reset();
List<Object> ids = DB.find(Customer.class).findIds();
assertEquals(ids.size(), 4);
DB.getDefault().pluginApi().cacheManager().clearAll();
// hit database
LoggedSql.start();
DB.find(Customer.class).where().idIn(ids).findMap();
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
// hit beanCache
LoggedSql.start();
DB.find(Customer.class).where().idIn(ids).findMap();
sql = LoggedSql.stop();
assertThat(sql).hasSize(0);
}
}
@@ -7,10 +7,12 @@ import io.ebeaninternal.api.SpiPersistenceContext;
import io.ebeaninternal.api.SpiTransaction;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.ContactNote;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@@ -20,6 +22,18 @@ import static org.junit.jupiter.api.Assertions.*;
class TestPersistenceContext extends BaseTestCase {
@Test
void testReload() {
ResetBasicData.reset();
try (Transaction txn = DB.beginTransaction()) {
List<ContactNote> notes = new ArrayList<>();
DB.find(ContactNote.class).findEach(notes::add);
notes.get(0).setTitle("FooBar");
DB.find(ContactNote.class).findList();
assertThat(notes.get(0).getTitle()).isEqualTo("FooBar");
}
}
@Test
void test() {
ResetBasicData.reset();
@@ -176,4 +190,30 @@ class TestPersistenceContext extends BaseTestCase {
assertThat(pc.toString()).contains("Customer=size:200 (0 weak)");
}
}
@Disabled // run manually
@Test
void testPcScopes_with_findEachFindList() {
for (int i = 0; i < 5000; i++) {
Customer c = new Customer();
c.setName("Customer #" + i);
DB.save(c);
Order o = new Order();
o.setCustomer(c);
DB.save(o);
}
for (int i = 0; i < 1000; i++) {
try (Transaction txn = DB.beginTransaction()) {
List<Customer> customers = new ArrayList<>();
DB.find(Customer.class).select("id").findEach(customers::add);
SpiPersistenceContext pc = ((SpiTransaction) txn).getPersistenceContext();
assertThat(pc.toString()).contains("Customer=size:5000 (5000 weak)");
customers.clear();
customers = DB.find(Customer.class).select("id").findList();
assertThat(pc.toString()).contains("Customer=size:5000"); // We expect ALWAYS 5000 entries in the PC
}
}
}
}
@@ -10,16 +10,16 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestExtraScalarTypes extends BaseTestCase {
class TestExtraScalarTypes extends BaseTestCase {
@Test
public void test() {
void test() {
Locale locale = Locale.getDefault();
Currency currency = Currency.getInstance(locale);
Locale locale = Locale.ENGLISH;
Currency currency = Currency.getInstance(Locale.US);
TimeZone tz = TimeZone.getDefault();
ESomeType e = new ESomeType();
@@ -29,20 +29,20 @@ public class TestExtraScalarTypes extends BaseTestCase {
DB.save(e);
ESomeType e2 = DB.find(ESomeType.class).setAutoTune(false).setId(e.getId()).findOne();
ESomeType e2 = DB.find(ESomeType.class).setId(e.getId()).findOne();
assertNotNull(e2.getCurrency());
assertNotNull(e2.getLocale());
assertNotNull(e2.getTimeZone());
List<ESomeType> list = DB.find(ESomeType.class)
.setAutoTune(false).where()
.where()
.eq("locale", locale)
.eq("timeZone", tz.getID())
.eq("currency", currency)
.findList();
assertTrue(!list.isEmpty());
assertThat(list).isNotEmpty();
}
}
@@ -4,7 +4,6 @@ import javax.persistence.Entity;
import javax.persistence.Inheritance;
@Entity
@Inheritance
public class Target1 extends TargetBase {
public Target1(String name) {
@@ -3,6 +3,9 @@ package org.tests.lazyforeignkeys;
import io.ebean.annotation.DbForeignKey;
import javax.persistence.*;
import org.tests.model.basic.Cat;
import java.util.UUID;
@@ -22,6 +25,11 @@ public class MainEntityRelation {
@JoinColumn(name = "id2")
@DbForeignKey(noConstraint = true)
private MainEntity entity2;
@ManyToOne
@JoinColumn(name = "cat_id")
@DbForeignKey(noConstraint = true)
private Cat cat;
private String attr1;
@@ -41,6 +49,14 @@ public class MainEntityRelation {
this.entity2 = entity2;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public String getAttr1() {
return attr1;
}
@@ -8,6 +8,7 @@ import io.ebean.text.PathProperties;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Cat;
import java.util.List;
@@ -56,7 +57,7 @@ public class TestLazyForeignKeys extends BaseTestCase {
List<String> sql = LoggedSql.stop();
assertThat(sql).hasSize(3);
assertSql(sql.get(0)).contains("select t0.id, t0.attr1, t0.id1, t0.id2 from main_entity_relation");
assertSql(sql.get(0)).contains("select t0.id, t0.attr1, t0.id1, t0.id2, t1.species, t0.cat_id from main_entity_relation t0 left join animal t1 on t1.id = t0.cat_id");
if (isSqlServer() || isOracle()) {
assertSql(sql.get(1)).contains("select t0.id, t0.attr1, t0.attr2, CASE WHEN t0.id is null THEN 1 ELSE 0 END from main_entity t0");
} else {
@@ -86,4 +87,17 @@ public class TestLazyForeignKeys extends BaseTestCase {
assertFalse(rel1.getEntity1().isDeleted());
assertTrue(rel1.getEntity2().isDeleted());
}
@Test
public void testGetWithDbForeignKey() {
MainEntityRelation relation = DB.find(MainEntityRelation.class).findOne();
Cat cat = new Cat();
cat.setId(123L);
relation.setCat(cat);
DB.save(relation);
relation = DB.find(MainEntityRelation.class).findOne();
assertNotNull(relation.getCat());
}
}
@@ -1,9 +1,6 @@
package org.tests.model.array;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.SqlRow;
import io.ebean.*;
import io.ebean.annotation.ForPlatform;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
@@ -272,4 +269,123 @@ public class TestDbArray_basic extends BaseTestCase {
assertThat(found.getUids()).hasSameElementsAs(uids);
assertThat(found.getStatuses()).hasSameElementsAs(statuses);
}
@Test
@ForPlatform(Platform.POSTGRES)
public void asDto_withArray() {
DB.find(EArrayBean.class).delete();
bean.setName("array in dto test");
List<String> phNumbers = bean.getPhoneNumbers();
phNumbers.add("4321");
phNumbers.add("9823");
List<Double> doubs = bean.getDoubs();
doubs.add(1.23);
doubs.add(4.56);
DB.save(bean);
// Data is saved correctly
LoggedSql.start();
DtoQuery<EArrayBeanDto> query = DB.find(EArrayBean.class)
// Interestingly writing `select("id,name,phone_numbers,doubs")`
// generates `select t0.id, t0.name, t0.id, t0.doubs`
// surprisingly changing unknown property to id
.select("id,name,phoneNumbers,doubs")
.asDto(EArrayBeanDto.class)
// Shouldn't be necessary
// But without it I see error
// Unable to map DB column phone_numbers to a property with a setter method on class org.tests.model.array.TestDbArray_basic$EArrayBeanDto
.setRelaxedMode();
List<EArrayBeanDto> dtos = query.findList();
List<String> sql = LoggedSql.stop();
assertSql(sql.get(0)).contains("select t0.id, t0.name, t0.phone_numbers, t0.doubs");
for (EArrayBeanDto dto : dtos) {
assertThat(dto.id).isNotNull();
assertThat(dto.name).isNotNull();
// Failure: null
assertThat(dto.phoneNumbers).isNotNull();
// Failure: null
assertThat(dto.doubs).isNotNull();
}
}
@Test
@ForPlatform(Platform.POSTGRES)
public void sqlUpdate_withArray() {
DB.find(EArrayBean.class).delete();
bean.setName("array in sql update test");
DB.save(bean);
// Data is saved correctly
List<String> phNumbers = new ArrayList<>();
phNumbers.add("4321");
phNumbers.add("9823");
LoggedSql.start();
// Positional param works
SqlUpdate update1 = DB.sqlUpdate("UPDATE earray_bean SET phone_numbers = ?")
.setParameter(1, phNumbers);
update1.execute();
System.out.println("done");
// Named param fails with
// javax.persistence.PersistenceException:
// ERROR: syntax error at or near "$2"
SqlUpdate update2 = DB.sqlUpdate("UPDATE earray_bean SET phone_numbers = :pns")
.setArrayParameter("pns", phNumbers);
update2.execute();
found = DB.find(EArrayBean.class, bean.getId());
System.out.println(found);
assertEquals("array in sql update test", found.getName());
assertThat(found.getPhoneNumbers()).containsExactly("4321", "9823");
}
public static class EArrayBeanDto {
Integer id;
List<String> phoneNumbers;
List<Double> doubs;
String name;
@Override
public String toString() {
return "id:" + id + " name:" + name + " phoneNumbers:" + phoneNumbers + " doubs:" + doubs;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<String> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public List<Double> getDoubs() {
return doubs;
}
public void setDoubs(List<Double> doubs) {
this.doubs = doubs;
}
}
}
@@ -6,18 +6,19 @@ import io.ebean.Transaction;
import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
public class TestIdClassScalar extends BaseTestCase {
class TestIdClassScalar extends BaseTestCase {
private BUser user = new BUser("Fiona");
private BSite site = new BSite("avaje.io");
private final BUser user = new BUser("Fiona");
private final BSite site = new BSite("avaje.io");
@Test
public void testBEmbId_equalsHashcode() {
void testBEmbId_equalsHashcode() {
BEmbId a = new BEmbId(UUID.randomUUID(), UUID.randomUUID());
BEmbId b = new BEmbId(a.getSiteId(), a.getUserId());
@@ -35,13 +36,11 @@ public class TestIdClassScalar extends BaseTestCase {
assertThat(a).isNotEqualTo(d);
assertThat(a.hashCode()).isNotEqualTo(d.hashCode());
assertThat(a.hashCode()).isEqualTo(a.otherHash());
}
@Test
public void fetchMany() {
void fetchMany() {
UUID siteId = UUID.randomUUID();
UUID userId = UUID.randomUUID();
@@ -59,7 +58,7 @@ public class TestIdClassScalar extends BaseTestCase {
}
@Test
public void insertBatch() {
void insertBatch() {
UUID siteId = UUID.randomUUID();
UUID userId = UUID.randomUUID();
@@ -81,11 +80,9 @@ public class TestIdClassScalar extends BaseTestCase {
}
@Test
public void test() {
void test() {
DB.save(user);
DB.save(site);
insertUpdateBridgeD(user, site);
insertUpdateBridgeE(user, site);
}
@@ -94,7 +91,6 @@ public class TestIdClassScalar extends BaseTestCase {
* Test where matching by db column naming convention.
*/
private void insertUpdateBridgeD(BUser user, BSite site) {
LoggedSql.start();
BSiteUserD access = new BSiteUserD(BAccessLevel.ONE, site.id, user.id);
@@ -139,7 +135,6 @@ public class TestIdClassScalar extends BaseTestCase {
* Test where matching by db column naming convention.
*/
private void insertUpdateBridgeE(BUser user, BSite site) {
LoggedSql.start();
BSiteUserE access = new BSiteUserE(BAccessLevel.ONE, site, user);
@@ -181,4 +176,47 @@ public class TestIdClassScalar extends BaseTestCase {
assertSql(sql.get(1)).contains("update bsite_user_e set access_level=? where site_id=? and user_id=?");
}
@Test
void idClass_existsQuery() {
BUser user = new BUser("JunkUser2");
BSite site = new BSite("JunkSite2");
BSiteUserE access = new BSiteUserE(BAccessLevel.ONE, site, user);
DB.save(user);
DB.save(site);
DB.save(access);
boolean exists = DB.find(BSiteUserE.class)
.where().eq("user.id", user.id)
.exists();
assertThat(exists).isTrue();
assertThat(DB.find(BSiteUserE.class).where().eq("user.id", user.id).findCount()).isEqualTo(1);
DB.delete(access);
DB.deleteAll(Arrays.asList(user, site));
}
@Test
void idClass_existsQuery_scalarImportedProperties() {
BUser user = new BUser("JunkUser3");
BSite site = new BSite("JunkSite3");
DB.save(user);
DB.save(site);
BSiteUserD access = new BSiteUserD(BAccessLevel.ONE, site.id, user.id);
DB.save(access);
boolean exists = DB.find(BSiteUserD.class)
.where().eq("userId", user.id)
.exists();
assertThat(exists).isTrue();
assertThat(DB.find(BSiteUserD.class).where().eq("userId", user.id).findCount()).isEqualTo(1);
DB.delete(access);
DB.deleteAll(Arrays.asList(user, site));
}
}
@@ -10,11 +10,10 @@ import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
public class TestElementCollectionBasicSet extends BaseTestCase {
class TestElementCollectionBasicSet extends BaseTestCase {
@Test
public void test() {
void test() {
LoggedSql.start();
EcsPerson person = new EcsPerson("Fiona021");
@@ -172,8 +171,7 @@ public class TestElementCollectionBasicSet extends BaseTestCase {
}
@Test
public void json() {
void json() {
EcsPerson person = new EcsPerson("Fiona021");
person.getPhoneNumbers().add("021 1234");
person.getPhoneNumbers().add("021 4321");
@@ -47,15 +47,10 @@ public class TestTextJsonReferenceBean extends BaseTestCase {
prodDesc.isReference(eb._ebean_getIntercept());
BeanState beanState = DB.beanState(refProd);
assertTrue(beanState.isNew());
assertTrue(beanState.isReference());
String name = refProd.getName();
assertNull(name);
// Set to be 'loaded' to invoke lazy loading
beanState.setLoaded();
String name2 = refProd.getName();
assertNotNull(name2);
assertNotNull(name);
}
List<Order> orders = DB.find(Order.class)
@@ -25,7 +25,7 @@ ebean.packages=org.tests,org.etest
datasource.default=h2
#datasource.h2.capturestacktrace=true
ebean.dumpMetricsOnShutdown=true
#ebean.dumpMetricsOnShutdown=true
ebean.dumpMetricsOptions=sql,hash,loc
#ebean.queryPlan.thresholdMicros=1000
ebean.queryPlan.enable=true
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>ebean composite</name>
@@ -22,20 +22,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
</dependency>
</dependencies>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>kotlin querybean generator</name>
@@ -29,7 +29,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
@@ -43,7 +43,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
@@ -64,7 +64,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<scope>test</scope>
</dependency>
+5 -5
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId>
<version>12.12.3</version>
<version>12.13.1</version>
<packaging>pom</packaging>
<name>ebean parent</name>
@@ -18,7 +18,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.3</tag>
<tag>ebean-parent-12.13.1</tag>
</scm>
<licenses>
@@ -38,15 +38,15 @@
</developers>
<properties>
<nexus.staging.autoReleaseAfterClose>true</nexus.staging.autoReleaseAfterClose>
<nexus.staging.autoReleaseAfterClose>false</nexus.staging.autoReleaseAfterClose>
<jackson.version>2.12.1</jackson.version>
<ebean-ddl-runner.version>1.2</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.1</ebean-migration-auto.version>
<ebean-migration.version>12.12.1</ebean-migration.version>
<ebean-test-docker.version>4.2</ebean-test-docker.version>
<ebean-datasource.version>7.3</ebean-datasource.version>
<ebean-agent.version>12.12.2</ebean-agent.version>
<ebean-maven-plugin.version>12.12.2</ebean-maven-plugin.version>
<ebean-agent.version>12.13.0</ebean-agent.version>
<ebean-maven-plugin.version>12.13.0</ebean-maven-plugin.version>
</properties>
<dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.3</version>
<version>12.13.1</version>
</parent>
<name>querybean generator</name>
+4
View File
@@ -15,6 +15,10 @@
<name>tests</name>
<description>test modules</description>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<modules>
<!-- test-java16 REQUIRES JDK 16 to run -->
<!-- <module>test-java16</module>-->
+4 -3
View File
@@ -13,13 +13,14 @@
<properties>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.12.3-SNAPSHOT</version>
<version>12.13.0-SNAPSHOT</version>
</dependency>
<dependency>
@@ -31,7 +32,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3-SNAPSHOT</version>
<version>12.13.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
@@ -57,7 +58,7 @@
<path>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.3-SNAPSHOT</version>
<version>12.13.0-SNAPSHOT</version>
</path>
</annotationProcessorPaths>
</configuration>
+4 -3
View File
@@ -18,9 +18,10 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<ebean-maven-plugin.version>12.12.1</ebean-maven-plugin.version>
<ebean-maven-plugin.version>12.13.0</ebean-maven-plugin.version>
<kotlin.version>1.5.31</kotlin.version>
<jackson.version>2.12.1</jackson.version>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
@@ -34,14 +35,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.3-SNAPSHOT</version>
<version>12.13.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.3-SNAPSHOT</version>
<version>12.13.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>