Skip to content

Commit 2486d4e

Browse files
committed
Progress
1 parent 4798309 commit 2486d4e

File tree

24 files changed

+300
-64
lines changed

24 files changed

+300
-64
lines changed

data-hibernate-jpa/src/main/java/io/micronaut/data/hibernate/operations/HibernateJpaOperations.java

+14-2
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,20 @@ public <T> Iterable<T> persistAll(@NonNull InsertBatchOperation<T> operation) {
488488
if (storedQuery != null) {
489489
return executeUpdate(operation, session, storedQuery);
490490
}
491-
for (T entity : operation) {
492-
session.persist(entity);
491+
if (persistOrMergeOnSave) {
492+
RuntimePersistentEntity<T> persistentEntity = getEntity(operation.getRootEntity());
493+
RuntimePersistentProperty<T> identity = persistentEntity.getIdentity();
494+
for (T entity : operation) {
495+
if (identity != null && identity.getProperty().get(entity) == null) {
496+
session.persist(entity);
497+
} else {
498+
session.merge(entity);
499+
}
500+
}
501+
} else {
502+
for (T entity : operation) {
503+
session.persist(entity);
504+
}
493505
}
494506
flushIfNecessary(session, operation.getAnnotationMetadata());
495507
return operation;

data-jdbc/src/main/java/io/micronaut/data/jdbc/config/DataJdbcConfiguration.java

+21
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import io.micronaut.context.annotation.EachProperty;
1919
import io.micronaut.context.annotation.Parameter;
20+
import io.micronaut.core.annotation.NextMajorVersion;
2021
import io.micronaut.core.annotation.NonNull;
2122
import io.micronaut.core.annotation.Nullable;
2223
import io.micronaut.core.naming.Named;
@@ -56,6 +57,12 @@ public class DataJdbcConfiguration implements Named, Toggleable {
5657
private boolean allowConnectionPerOperation = true;
5758
private boolean enabled = true;
5859

60+
/**
61+
* Fail on multiple results for findOne.
62+
*/
63+
@NextMajorVersion("Make the default")
64+
private boolean uniqueResultOnFindOne;
65+
5966
/**
6067
* The configuration.
6168
* @param name The configuration name
@@ -190,4 +197,18 @@ public boolean isEnabled() {
190197
public void setEnabled(boolean enabled) {
191198
this.enabled = enabled;
192199
}
200+
201+
/**
202+
* @return Is unique result required on find one
203+
*/
204+
public boolean isUniqueResultOnFindOne() {
205+
return uniqueResultOnFindOne;
206+
}
207+
208+
/**
209+
* @param uniqueResultOnFindOne Is unique result required on find one
210+
*/
211+
public void setUniqueResultOnFindOne(boolean uniqueResultOnFindOne) {
212+
this.uniqueResultOnFindOne = uniqueResultOnFindOne;
213+
}
193214
}

data-jdbc/src/main/java/io/micronaut/data/jdbc/operations/DefaultJdbcRepositoryOperations.java

+13-11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import io.micronaut.data.connection.ConnectionStatus;
3535
import io.micronaut.data.connection.annotation.Connectable;
3636
import io.micronaut.data.exceptions.DataAccessException;
37+
import io.micronaut.data.exceptions.NonUniqueResultException;
3738
import io.micronaut.data.jdbc.config.DataJdbcConfiguration;
3839
import io.micronaut.data.jdbc.convert.JdbcConversionContext;
3940
import io.micronaut.data.jdbc.mapper.ColumnIndexCallableResultReader;
@@ -165,6 +166,7 @@ public final class DefaultJdbcRepositoryOperations extends AbstractSqlRepository
165166
private final ColumnIndexCallableResultReader columnIndexCallableResultReader;
166167
private final Map<Dialect, List<SqlExceptionMapper>> sqlExceptionMappers = new EnumMap<>(Dialect.class);
167168

169+
168170
/**
169171
* Default constructor.
170172
*
@@ -353,7 +355,8 @@ public <T, R> R findOne(@NonNull PreparedQuery<T, R> pq) {
353355
}
354356

355357
private <T, R> R findOne(Connection connection, SqlPreparedQuery<T, R> preparedQuery) {
356-
try (PreparedStatement ps = prepareStatement(connection::prepareStatement, preparedQuery, false, true)) {
358+
boolean limitToSingleResult = !jdbcConfiguration.isUniqueResultOnFindOne();
359+
try (PreparedStatement ps = prepareStatement(connection::prepareStatement, preparedQuery, false, limitToSingleResult)) {
357360
preparedQuery.bindParameters(new JdbcParameterBinder(connection, ps, preparedQuery));
358361
try (ResultSet rs = ps.executeQuery()) {
359362
SqlTypeMapper<ResultSet, R> mapper = createMapper(preparedQuery, ResultSet.class);
@@ -365,12 +368,19 @@ private <T, R> R findOne(Connection connection, SqlPreparedQuery<T, R> preparedQ
365368
if (rs.next()) {
366369
oneMapper.processRow(rs);
367370
}
368-
while (hasJoins && rs.next()) {
369-
oneMapper.processRow(rs);
371+
if (hasJoins) {
372+
while (rs.next()) {
373+
oneMapper.processRow(rs);
374+
}
375+
} else if (jdbcConfiguration.isUniqueResultOnFindOne() && rs.next()) {
376+
throw new NonUniqueResultException("Multiple results found for query: " + preparedQuery.getQuery());
370377
}
371378
result = oneMapper.getResult();
372379
} else if (rs.next()) {
373380
result = mapper.map(rs, preparedQuery.getResultType());
381+
if (jdbcConfiguration.isUniqueResultOnFindOne() && rs.next()) {
382+
throw new NonUniqueResultException("Multiple results found for query: " + preparedQuery.getQuery());
383+
}
374384
} else {
375385
result = null;
376386
}
@@ -720,14 +730,6 @@ public <T> T persist(@NonNull InsertOperation<T> operation) {
720730
final SqlStoredQuery<T, ?> storedQuery = getSqlStoredQuery(operation.getStoredQuery());
721731
JdbcOperationContext ctx = createContext(operation, connection, storedQuery);
722732
JdbcEntityOperations<T> op = new JdbcEntityOperations<>(ctx, storedQuery, storedQuery.getPersistentEntity(), operation.getEntity(), true);
723-
// RuntimePersistentEntity<T> persistentEntity = getEntity(operation.getRootEntity());
724-
// if (persistentEntity.hasIdentity()) {
725-
// if (!persistentEntity.getIdentity().isAutoPopulated()
726-
// && persistentEntity.getIdentity().getProperty().get(operation.getEntity()) != null) {
727-
// op.update();
728-
// return op;
729-
// }
730-
// }
731733
op.persist();
732734
return op;
733735
}, operation.getInvocationContext()).getEntity();

data-processor/src/main/java/io/micronaut/data/processor/visitors/finders/annotated/DeleteAnnotatedMethodMatcher.java

+14-17
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,24 @@ public MethodMatch match(MethodMatchContext matchContext) {
6464
ParameterElement finalEntityParameter = entityParameter;
6565
ParameterElement finalEntitiesParameter = entitiesParameter;
6666

67-
if (finalEntitiesParameter != null || finalEntityParameter != null) {
68-
return new DeleteCriteriaMethodMatch(List.of(), false) {
67+
return new DeleteCriteriaMethodMatch(List.of(), false) {
6968

70-
@Override
71-
protected boolean supportedByImplicitQueries() {
72-
return true;
73-
}
69+
@Override
70+
protected boolean supportedByImplicitQueries() {
71+
return finalEntityParameter != null || finalEntitiesParameter != null;
72+
}
7473

75-
@Override
76-
protected ParameterElement getEntityParameter() {
77-
return finalEntityParameter;
78-
}
74+
@Override
75+
protected ParameterElement getEntityParameter() {
76+
return finalEntityParameter;
77+
}
7978

80-
@Override
81-
protected ParameterElement getEntitiesParameter() {
82-
return finalEntitiesParameter;
83-
}
79+
@Override
80+
protected ParameterElement getEntitiesParameter() {
81+
return finalEntitiesParameter;
82+
}
8483

85-
};
86-
}
87-
throw new ProcessingException(matchContext.getMethodElement(), "Delete method should include an entity to update");
84+
};
8885
}
8986
return null;
9087
}

jakarta-data-tck/hibernate/build.gradle

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ plugins {
55
}
66

77
dependencies {
8+
testAnnotationProcessor mn.micronaut.inject.java
9+
testAnnotationProcessor projects.micronautDataProcessor
810

911
testImplementation projects.micronautJakartaDataTck.micronautSupport
1012
testImplementation projects.micronautDataHibernateJpa
11-
testImplementation (projects.micronautDataProcessor) {
12-
exclude group: 'org.antlr'
13-
}
13+
testImplementation projects.micronautDataProcessor
14+
testImplementation mnValidation.micronaut.validation.processor
15+
testImplementation mnValidation.micronaut.validation
16+
1417
testRuntimeOnly mnTest.junit.jupiter.engine
1518
testRuntimeOnly mnSql.micronaut.jdbc.tomcat
1619
testRuntimeOnly mnLogging.logback.classic

jakarta-data-tck/hibernate/src/main/resources/exclusions.txt

Whitespace-only changes.

jakarta-data-tck/hibernate/src/main/resources/junit-platform.properties

-2
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.micronaut.data.jakarta.tck;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.Id;
5+
6+
// Prevent Hibernate failing for tests without entities
7+
@Entity
8+
public class DummyBean {
9+
10+
@Id
11+
private Long id;
12+
private String name;
13+
14+
public Long getId() {
15+
return id;
16+
}
17+
18+
public void setId(Long id) {
19+
this.id = id;
20+
}
21+
22+
public String getName() {
23+
return name;
24+
}
25+
26+
public void setName(String name) {
27+
this.name = name;
28+
}
29+
}

jakarta-data-tck/hibernate/src/test/java/io/micronaut/data/jakarta/tck/FilterExtension.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
public class FilterExtension implements ExecutionCondition {
1212
private static final ConditionEvaluationResult DISABLED = ConditionEvaluationResult.disabled("DISABLED");
1313

14-
public FilterExtension() throws Exception {
14+
public FilterExtension() {
1515
}
1616

1717
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package io.micronaut.data.jakarta.tck;
2+
3+
import org.junit.platform.suite.api.IncludeClassNamePatterns;
4+
import org.junit.platform.suite.api.SelectPackages;
5+
import org.junit.platform.suite.api.Suite;
6+
7+
public class HibernateJakartaDataTCKSuite {
8+
9+
@Suite
10+
@SelectPackages("ee.jakarta.tck.data")
11+
@IncludeClassNamePatterns("ee.jakarta.tck.data.standalone.entity.*")
12+
public static class EntityTests {
13+
}
14+
15+
@Suite
16+
@SelectPackages("ee.jakarta.tck.data")
17+
@IncludeClassNamePatterns("ee.jakarta.tck.data.standalone.persistence.*")
18+
public static class PersistenceTests {
19+
}
20+
21+
@Suite
22+
@SelectPackages("ee.jakarta.tck.data")
23+
@IncludeClassNamePatterns("ee.jakarta.tck.data.web.validation.*")
24+
public static class ValidationTests {
25+
}
26+
27+
}

jakarta-data-tck/hibernate/src/test/java/io/micronaut/data/jakarta/tck/LoggingConfig.java

-14
This file was deleted.

jakarta-data-tck/hibernate/src/test/resources/application.yml

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ datasources:
1212
jpa:
1313
default:
1414
properties:
15+
uniqueResultOnFindOne: true
16+
persistOrMergeOnSave: true
1517
hibernate:
1618
show_sql: true
1719
hbm2ddl:

jakarta-data-tck/hibernate/src/test/resources/logback.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</root>
1515

1616
<logger name="org.jboss.arquillian" level="debug"/>
17-
<logger name="io.micronaut.data.query" level="TRACE"/>
17+
<!-- <logger name="io.micronaut.data.query" level="TRACE"/>-->
1818
<logger name="io.micronaut" level="info"/>
1919

2020
</configuration>

jakarta-data-tck/jdbc/build.gradle

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
plugins {
2+
id "java-library"
3+
id "io.micronaut.build.internal.data-base"
4+
id "io.micronaut.build.internal.data-dependencies"
5+
}
6+
7+
dependencies {
8+
9+
testImplementation projects.micronautJakartaDataTck.micronautSupport
10+
testImplementation projects.micronautDataJdbc
11+
testImplementation projects.micronautDataProcessor
12+
testImplementation mnValidation.micronaut.validation.processor
13+
testImplementation mnValidation.micronaut.validation
14+
15+
testRuntimeOnly mnTest.junit.jupiter.engine
16+
testRuntimeOnly mnSql.micronaut.jdbc.tomcat
17+
testRuntimeOnly mnLogging.logback.classic
18+
testRuntimeOnly mnSql.h2
19+
testRuntimeOnly mn.snakeyaml
20+
}
21+
22+
test {
23+
scanForTestClasses false
24+
systemProperty("junit.jupiter.extensions.autodetection.enabled", "true")
25+
useJUnitPlatform()
26+
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.micronaut.data.jakarta.tck;
2+
3+
import ee.jakarta.tck.data.standalone.entity.EntityTests;
4+
import ee.jakarta.tck.data.standalone.persistence.PersistenceEntityTests;
5+
import ee.jakarta.tck.data.web.validation.ValidationTests;
6+
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
7+
import org.junit.jupiter.api.extension.ExecutionCondition;
8+
import org.junit.jupiter.api.extension.ExtensionContext;
9+
10+
import java.lang.reflect.Method;
11+
12+
public class FilterExtension implements ExecutionCondition {
13+
private static final ConditionEvaluationResult DISABLED = ConditionEvaluationResult.disabled("DISABLED");
14+
15+
public FilterExtension() {
16+
}
17+
18+
@Override
19+
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
20+
Class<?> testClass = context.getTestClass().orElse(null);
21+
String testMethodName = context.getTestMethod().map(Method::getName).orElse("");
22+
if (testClass == EntityTests.class) {
23+
switch (testMethodName) {
24+
case "testBasicRepositoryBuiltInMethods", "testBasicRepositoryMethods" -> {
25+
return DISABLED; // Support deciding between persist or update when save is called
26+
}
27+
28+
}
29+
}
30+
if (testClass == ValidationTests.class) {
31+
switch (testMethodName) {
32+
case "testSaveWithValidConstraints", "testUpdateAllWithValidConstraints", "testUpdateWithValidConstraints" -> {
33+
return DISABLED; // Support deciding between persist or update when save is called
34+
}
35+
36+
}
37+
}
38+
return ConditionEvaluationResult.enabled(null);
39+
}
40+
41+
}

jakarta-data-tck/hibernate/src/test/java/io/micronaut/data/jakarta/tck/JakartaDataTCKSuite.java jakarta-data-tck/jdbc/src/test/java/io/micronaut/data/jakarta/tck/MicronautJdbcDataTCKSuite.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,24 @@
44
import org.junit.platform.suite.api.SelectPackages;
55
import org.junit.platform.suite.api.Suite;
66

7-
public class JakartaDataTCKSuite {
7+
public class MicronautJdbcDataTCKSuite {
88

99
@Suite
1010
@SelectPackages("ee.jakarta.tck.data")
1111
@IncludeClassNamePatterns("ee.jakarta.tck.data.standalone.entity.*")
1212
public static class EntityTests {
1313
}
1414

15-
1615
@Suite
1716
@SelectPackages("ee.jakarta.tck.data")
1817
@IncludeClassNamePatterns("ee.jakarta.tck.data.standalone.persistence.*")
1918
public static class PersistenceTests {
2019
}
2120

21+
@Suite
22+
@SelectPackages("ee.jakarta.tck.data")
23+
@IncludeClassNamePatterns("ee.jakarta.tck.data.web.validation.*")
24+
public static class ValidationTests {
25+
}
2226

2327
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.micronaut.data.jakarta.tck.FilterExtension

0 commit comments

Comments
 (0)