Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 4.1 #2554

Merged
merged 25 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c1e7fe7
fix(deps): update dependency io.micronaut.validation:micronaut-valida…
renovate[bot] Sep 5, 2023
9c347f2
fix(deps): update dependency io.micronaut:micronaut-core-bom to v4.1.…
renovate[bot] Sep 5, 2023
2a1c517
fix(deps): update dependency io.micronaut.spring:micronaut-spring-bom…
renovate[bot] Sep 5, 2023
64acd03
chore(deps): update graalvm/setup-graalvm action to v1.1.3 (#2493)
renovate[bot] Sep 7, 2023
6e9e86a
chore(deps): update dependency gradle to v8.3 (#2481)
renovate[bot] Sep 8, 2023
6db84e3
Update common files (#2499)
micronaut-build Sep 11, 2023
6b60fd5
fix(deps): update dependency io.micronaut.multitenancy:micronaut-mult…
renovate[bot] Sep 12, 2023
483795a
fix(deps): update dependency io.micronaut.validation:micronaut-valida…
renovate[bot] Sep 12, 2023
fd84f66
fix(deps): update dependency io.micronaut:micronaut-core-bom to v4.1.…
renovate[bot] Sep 12, 2023
041af7d
fix(deps): update dependency io.micronaut.logging:micronaut-logging-b…
renovate[bot] Sep 12, 2023
b4c41dd
fix(deps): update dependency io.micronaut.kotlin:micronaut-kotlin-bom…
renovate[bot] Sep 12, 2023
03df22b
Update common files (#2511)
micronaut-build Sep 13, 2023
e041f46
fix(deps): update dependency io.micronaut:micronaut-core-bom to v4.1.…
renovate[bot] Sep 13, 2023
d15252f
fix(deps): update dependency org.apache.groovy:groovy-dateutil to v4.…
renovate[bot] Sep 15, 2023
6de567f
fix(deps): update spring data (#2517)
renovate[bot] Sep 15, 2023
3577af8
bug: JPA if native use createNativeMutationQuery (#2520)
sdelamo Sep 18, 2023
9ec16c9
doc: how to use Spring JdbcTemplate, with multi-language examples. (#…
wetted Sep 18, 2023
ed8b1a8
test: use transactionManager instead of transaction-manager
sdelamo Sep 19, 2023
c1262ac
[skip ci] Release v4.1.3
micronaut-build Sep 19, 2023
edfceec
Back to 4.1.4-SNAPSHOT
micronaut-build Sep 19, 2023
3ca5e1f
Fix JPA sort issue for embedded field (#2550)
radovanradic Oct 9, 2023
8b18b81
[skip ci] Release v4.1.4
micronaut-build Oct 9, 2023
8100ccb
Back to 4.1.5-SNAPSHOT
micronaut-build Oct 9, 2023
d08eb6a
Merge remote-tracking branch 'origin/4.1.x' into mr
dstepanov Oct 10, 2023
78451e0
Correct docs
dstepanov Oct 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ abstract class AbstractHibernateQuerySpec extends AbstractQuerySpec {
def found = userWithWhereRepository.findById(e.id)
then:
found.isPresent()
cleanup:
userWithWhereRepository.deleteById(e.id)
}

void "test @where on find one deleted"() {
Expand Down Expand Up @@ -729,6 +731,28 @@ abstract class AbstractHibernateQuerySpec extends AbstractQuerySpec {
result.size() == 0
}

void "test order by embedded field"() {
when:
def e1 = userWithWhereRepository.save(new UserWithWhere(id: UUID.randomUUID(), email: "where1@somewhere.com", deleted: false))
def u2 = new UserWithWhere(id: UUID.randomUUID(), email: "where2@somewhere.com", deleted: false)
u2.audit.createdTime = u2.audit.createdTime.plusSeconds(30)
def e2 = userWithWhereRepository.save(u2)
def found1 = userWithWhereRepository.findById(e1.id)
def found2 = userWithWhereRepository.findById(e2.id)
then:
found1.present
found2.present
when:"Sorted by embedded field works"
def sortedItems = userWithWhereRepository.findAllByIdInList(List.of(e1.id, e2.id), Sort.of(Sort.Order.desc("audit.createdTime", false)))
then:
sortedItems
sortedItems.size() == 2
sortedItems[0].id == e2.id
sortedItems[1].id == e1.id
cleanup:
userWithWhereRepository.deleteAll(List.of(e1, e2))
}

private static Specification<Book> testJoin(String value) {
return ((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.join("author").get("name"), value))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package io.micronaut.data.hibernate;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.data.annotation.Repository;
import io.micronaut.data.hibernate.entities.UserWithWhere;
import io.micronaut.data.model.Sort;
import io.micronaut.data.repository.CrudRepository;

import java.util.List;
import java.util.UUID;

@Repository
public interface UserWithWhereRepository extends CrudRepository<UserWithWhere, UUID> {

List<UserWithWhere> findAllByIdInList(List<UUID> ids, @NonNull Sort sort);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.micronaut.data.hibernate.entities;

import io.micronaut.data.annotation.Embeddable;

import java.time.Instant;

@Embeddable
public class Audit {

private Instant createdTime = Instant.now();

private String createdBy = "current";

public Instant getCreatedTime() {
return createdTime;
}

public void setCreatedTime(Instant createdTime) {
this.createdTime = createdTime;
}

public String getCreatedBy() {
return createdBy;
}

public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package io.micronaut.data.hibernate.entities;

import io.micronaut.data.annotation.Embeddable;
import io.micronaut.data.annotation.Where;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
Expand All @@ -17,6 +19,8 @@ public class UserWithWhere {
private UUID id;
private String email;
private Boolean deleted;
@Embedded
private Audit audit = new Audit();

public UUID getId() {
return id;
Expand All @@ -41,4 +45,12 @@ public Boolean getDeleted() {
public void setDeleted(Boolean deleted) {
this.deleted = deleted;
}

public Audit getAudit() {
return audit;
}

public void setAudit(Audit audit) {
this.audit = audit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1928,7 +1928,8 @@ public QueryResult buildOrderBy(String query, @NonNull PersistentEntity entity,
List<Association> associations = new ArrayList<>(path.getAssociations());
int assocCount = associations.size();
// If last association is embedded, it does not need to be joined to the alias since it will be in the destination table
if (assocCount > 0 && associations.get(assocCount - 1) instanceof Embedded) {
// JPA/Hibernate is special case and in that case we leave association for specific handling below
if (assocCount > 0 && computePropertyPaths() && associations.get(assocCount - 1) instanceof Embedded) {
associations.remove(assocCount - 1);
}
if (associations.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import javax.sql.DataSource
@JdbcRepository(dialect = Dialect.H2)
abstract class AbstractBookRepository implements CrudRepository<@Valid Book, @NotNull Long> {

private final JdbcTemplate jdbcTemplate
private final JdbcTemplate jdbcTemplate;

AbstractBookRepository(JdbcTemplate jdbcTemplate) { // <1>
this.jdbcTemplate = jdbcTemplate
AbstractBookRepository(DataSource dataSource) { // <1>
this.jdbcTemplate = new JdbcTemplate(DelegatingDataSource.unwrapDataSource(dataSource)); //<2>
}

@Transactional
List<Book> findByTitle(@NonNull @NotNull String title) {
return jdbcTemplate.queryForList('SELECT * FROM Book AS book WHERE book.title = ?', title) // <2>
return jdbcTemplate.queryForList('SELECT * FROM Book AS book WHERE book.title = ?', title) // <3>
.collect(m -> new Book(m.id as Long, m.title as String, m.pages as Integer))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import spock.lang.Specification
@MicronautTest(transactional = false)
@Property(name = 'spec.name', value = 'BookRepositorySpec')
@Property(name = 'datasources.default.name', value = 'mydb')
@Property(name = 'datasources.default.transaction-manager', value = 'springJdbc')
@Property(name = 'datasources.default.transactionManager', value = 'springJdbc')
@Property(name = 'jpa.default.properties.hibernate.hbm2ddl.auto', value = 'create-drop')
class BookRepositorySpec extends Specification {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.NonNull;
import io.micronaut.data.connection.jdbc.advice.DelegatingDataSource;
import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.repository.CrudRepository;
Expand All @@ -20,13 +21,13 @@ public abstract class AbstractBookRepository implements CrudRepository<@Valid Bo

private final JdbcTemplate jdbcTemplate;

public AbstractBookRepository(JdbcTemplate jdbcTemplate) { // <1>
this.jdbcTemplate = jdbcTemplate;
public AbstractBookRepository(DataSource dataSource) { // <1>
this.jdbcTemplate = new JdbcTemplate(DelegatingDataSource.unwrapDataSource(dataSource)); //<2>
}

@Transactional
public List<Book> findByTitle(@NonNull @NotNull String title) {
return jdbcTemplate.queryForList("SELECT * FROM Book AS book WHERE book.title = ?", title) // <2>
return jdbcTemplate.queryForList("SELECT * FROM Book AS book WHERE book.title = ?", title) // <3>
.stream()
.map(m -> new Book((Long) m.get("id"), (String) m.get("title"), (Integer) m.get("pages")))
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@MicronautTest
@Property(name = "spec.name", value = "BookRepositoryTest")
@Property(name = "datasources.default.name", value = "mydb")
@Property(name = "datasources.default.transaction-manager", value = "springJdbc")
@Property(name = "datasources.default.transactionManager", value = "springJdbc")
@Property(name = "jpa.default.properties.hibernate.hbm2ddl.auto", value = "create-drop")
class BookRepositoryTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import org.springframework.jdbc.core.JdbcTemplate
@Requires(property = "spec.name", value = "BookRepositoryTest") // tag::clazz[]
// tag::clazz[]
@JdbcRepository(dialect = Dialect.H2)
abstract class AbstractBookRepository(val jdbcTemplate: JdbcTemplate) : CrudRepository<@Valid Book, Long> { //<1>
abstract class AbstractBookRepository(dataSource: DataSource) : CrudRepository<@Valid Book, Long> { // <1>

private val jdbcTemplate: JdbcTemplate = JdbcTemplate(DelegatingDataSource.unwrapDataSource(dataSource)) //<2>

@Transactional
open fun findByTitle(title: String) = jdbcTemplate
.queryForList("SELECT * FROM Book AS book WHERE book.title = ?", title) // <2>
.queryForList("SELECT * FROM Book AS book WHERE book.title = ?", title) // <3>
.map { m -> Book(m["id"] as Long, m["title"] as String, m["pages"] as Int) }
}
// end::clazz[]
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test
@MicronautTest
@Property(name = "spec.name", value = "BookRepositoryTest")
@Property(name = "datasources.default.name", value = "mydb")
@Property(name = "datasources.default.transaction-manager", value = "springJdbc")
@Property(name = "datasources.default.transactionManager", value = "springJdbc")
@Property(name = "jpa.default.properties.hibernate.hbm2ddl.auto", value = "create-drop")
internal class BookRepositoryTest {

Expand Down
5 changes: 3 additions & 2 deletions src/main/docs/guide/dbc/dbcRepositories.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ The following code illustrates an example that integrates a `JdbcTemplate` insta

snippet::example.AbstractBookRepository[project-base="doc-examples/jdbc-spring-template-example",source="main",tags="clazz"]

<1> Inject the `org.springframework.jdbc.core.JdbcTemplate` configured by the application.
<2> Now the `JdbcTemplate` API can be used to implement repository methods.
<1> Inject the `java.sql.DataSource` configured by the application.
<2> Instantiate a `JdbcTemplate` object using the injected `DataSource`.
<3> Now the `JdbcTemplate` API can be used to implement repository methods.

In addition, the transaction manager for Spring JDBC needs to be set in application configuration.

Expand Down