Skip to content

Commit

Permalink
Merge pull request #3285 from micronaut-projects/merge-4-10-x
Browse files Browse the repository at this point in the history
Merge 4.10.x into 4.11.x
  • Loading branch information
dstepanov authored Jan 14, 2025
2 parents e67ac69 + 5af7fdc commit f874753
Show file tree
Hide file tree
Showing 33 changed files with 385 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,16 @@ private boolean containsColumnName(ResultSet resultSet, String name) {
int columnsCount = rsmd.getColumnCount();
knownColumns = CollectionUtils.newHashSet(columnsCount);
for (int x = 1; x <= columnsCount; x++) {
knownColumns.add(rsmd.getColumnLabel(x).toLowerCase());
knownColumns.add(toLowerCase(rsmd.getColumnLabel(x)));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return knownColumns.contains(name);
return knownColumns.contains(toLowerCase(name));
}

private static String toLowerCase(String str) {
return str == null ? null : str.toLowerCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class H2RepositorySpec extends AbstractRepositorySpec implements H2TestPropertyP
@Shared
H2BookEntityRepository bookEntityRepository = context.getBean(H2BookEntityRepository)

@Shared
H2ExampleEntityRepository exampleEntityRepo = context.getBean(H2ExampleEntityRepository)

@Override
EntityWithIdClassRepository getEntityWithIdClassRepository() {
return entityWithIdClassRepo
Expand Down Expand Up @@ -221,6 +224,11 @@ class H2RepositorySpec extends AbstractRepositorySpec implements H2TestPropertyP
return pageRepo
}

@Override
ExampleEntityRepository getExampleEntityRepository() {
return exampleEntityRepo
}

@Override
boolean isSupportsArrays() {
return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ class MariaRepositorySpec extends AbstractRepositorySpec implements MariaTestPro
return context.getBean(MySqlEntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(MySqlExampleEntityRepository)
}

@Override
protected boolean skipCustomSchemaAndCatalogTest() {
// INSERT command denied to user 'test'@'172.17.0.1' for table 'cars'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ class MySqlRepositorySpec extends AbstractRepositorySpec implements MySQLTestPro
return context.getBean(MySqlEntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(MySqlExampleEntityRepository)
}

def "for update is in the correct location"() {
given:
setupBooks()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ class OracleXERepositorySpec extends AbstractRepositorySpec implements OracleTes
return context.getBean(OracleXEEntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(OracleExampleEntityRepository)
}

@Override
protected boolean skipCustomSchemaAndCatalogTest() {
// ORA-04043: object "FORD"."CARS" does not exist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ class PostgresRepositorySpec extends AbstractRepositorySpec implements PostgresT
return context.getBean(PostgresEntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(PostgresExampleEntityRepository)
}

@Memoized
@Override
boolean isSupportsArrays() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,10 @@ class SqlServerRepositorySpec extends AbstractRepositorySpec implements MSSQLTes
EntityWithIdClass2Repository getEntityWithIdClass2Repository() {
return context.getBean(MSEntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(MSExampleEntityRepository)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.data.jdbc.h2;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.repositories.ExampleEntityRepository;

@JdbcRepository(dialect = Dialect.H2)
public interface H2ExampleEntityRepository extends ExampleEntityRepository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.data.jdbc.mysql;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.repositories.ExampleEntityRepository;

@JdbcRepository(dialect = Dialect.MYSQL)
public interface MySqlExampleEntityRepository extends ExampleEntityRepository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.data.jdbc.oraclexe;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.repositories.ExampleEntityRepository;

@JdbcRepository(dialect = Dialect.ORACLE)
public interface OracleExampleEntityRepository extends ExampleEntityRepository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.data.jdbc.postgres;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.repositories.ExampleEntityRepository;

@JdbcRepository(dialect = Dialect.POSTGRES)
public interface PostgresExampleEntityRepository extends ExampleEntityRepository {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.micronaut.data.jdbc.sqlserver;

import io.micronaut.data.jdbc.annotation.JdbcRepository;
import io.micronaut.data.model.query.builder.sql.Dialect;
import io.micronaut.data.tck.repositories.ExampleEntityRepository;

@JdbcRepository(dialect = Dialect.SQL_SERVER)
public interface MSExampleEntityRepository extends ExampleEntityRepository {
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,21 @@ protected <R> R convertResult(CodecRegistry codecRegistry,
if (resultType == BsonDocument.class) {
return (R) result;
}
Optional<BeanIntrospection<R>> introspection = BeanIntrospector.SHARED.findIntrospection(resultType);
if (introspection.isPresent()) {
try {
return mapIntrospectedObject(result, resultType);
} catch (Exception e) {
LOG.warn("Failed to map @Introspection annotated result. " +
"Now attempting to fallback and read object from the document. Error: {}", e.getMessage());
}

Optional<R> maybeConverted = convertUsingIntrospected(result, resultType);
if (maybeConverted.isPresent()) {
return maybeConverted.get();
}

BsonValue value;
if (result == null) {
value = BsonNull.VALUE;
} else if (result.size() == 1) {
value = result.values().iterator().next();
} else if (result.size() == 2) {
Optional<Map.Entry<String, BsonValue>> id = result.entrySet().stream().filter(f -> !f.getKey().equals("_id")).findFirst();
if (id.isPresent()) {
value = id.get().getValue();
Optional<Map.Entry<String, BsonValue>> nonIdValue = result.entrySet().stream().filter(f -> !f.getKey().equals("_id")).findFirst();
if (nonIdValue.isPresent()) {
value = nonIdValue.get().getValue();
} else {
value = result.values().iterator().next();
}
Expand All @@ -196,6 +193,42 @@ protected <R> R convertResult(CodecRegistry codecRegistry,
return conversionService.convertRequired(MongoUtils.toValue(value), resultType);
}

/**
* Attempts to convert a BSON document into an instance of the specified result type using introspection.
*
* If the result type has been annotated with `@Introspection`, this method will attempt to use the provided
* `BeanIntrospection` to map the BSON document onto an instance of the result type.
*
* If the mapping fails or if no `BeanIntrospection` is found for the result type, an empty `Optional` is returned.
*
* @param result The BSON document containing the data to be mapped
* @param resultType The type of the object being mapped
* @param <R> The type parameter representing the result type
* @return An `Optional` containing the mapped object, or an empty `Optional` if mapping failed or no `BeanIntrospection` was found
*/
protected <R> Optional<R> convertUsingIntrospected(BsonDocument result, Class<R> resultType) {
Optional<BeanIntrospection<R>> introspection = BeanIntrospector.SHARED.findIntrospection(resultType);
if (introspection.isPresent()) {
try {
return Optional.of(mapIntrospectedObject(result, resultType));
} catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("Failed to map @Introspection annotated result. " +
"Now attempting to fallback and read object from the document. Error: {}", e.getMessage());
}
}
}
return Optional.empty();
}

/**
* Maps an introspected object from a BSON document.
*
* @param result The BSON document containing the data to be mapped
* @param resultType The type of the object being mapped
* @param <R> The type parameter representing the result type
* @return An instance of the specified result type, populated with data from the BSON document
*/
private <R> R mapIntrospectedObject(BsonDocument result, Class<R> resultType) {
return (new BeanIntrospectionMapper<BsonDocument, R>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import com.mongodb.client.model.Updates
import groovy.transform.Memoized
import io.micronaut.data.document.mongodb.entities.ComplexEntity
import io.micronaut.data.document.mongodb.entities.ComplexValue
import io.micronaut.data.document.mongodb.entities.Customer
import io.micronaut.data.document.mongodb.entities.ElementRow
import io.micronaut.data.document.mongodb.repositories.ComplexEntityRepository
import io.micronaut.data.document.mongodb.repositories.CustomerRepository
import io.micronaut.data.document.mongodb.repositories.ElementRowRepository
import io.micronaut.data.document.mongodb.repositories.MongoAuthorRepository
import io.micronaut.data.document.mongodb.repositories.MongoCriteriaPersonRepository
Expand Down Expand Up @@ -892,6 +894,23 @@ class MongoDocumentRepositorySpec extends AbstractDocumentRepositorySpec impleme
people.collect{ it.id }.containsAll(limitedPeople2.collect{ it.id })
}

void "test DTO retrieval"() {
when:
def customer = new Customer("1", "first", "last", List.of())
def saved = customerRepository.save(customer)
def loaded = customerRepository.findById(saved.id)
then:
loaded.present
loaded.get().id == saved.id
when:
def customerViews = customerRepository.viewFindAll();
then:
customerViews.size() == 1
customerViews[0].id == saved.id
cleanup:
customerRepository.deleteAll()
}

@Memoized
MongoExecutorPersonRepository getMongoExecutorPersonRepository() {
return context.getBean(MongoExecutorPersonRepository)
Expand Down Expand Up @@ -959,4 +978,9 @@ class MongoDocumentRepositorySpec extends AbstractDocumentRepositorySpec impleme
ComplexEntityRepository getComplexEntityRepository() {
return context.getBean(ComplexEntityRepository)
}

@Memoized
CustomerRepository getCustomerRepository() {
return context.getBean(CustomerRepository)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.micronaut.data.document.mongodb.entities;

public record ChangeLog(String message) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package io.micronaut.data.document.mongodb.entities;

import io.micronaut.data.annotation.GeneratedValue;
import io.micronaut.data.annotation.Id;
import io.micronaut.data.annotation.MappedEntity;

import java.util.List;

@MappedEntity
public final class Customer {
@Id
@GeneratedValue
private String id;
private String firstName;
private String lastName;

private List<ChangeLog> changeLogs;

public Customer() {
}

public Customer(String id, String firstName, String lastName, List<ChangeLog> changeLogs) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.changeLogs = changeLogs;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public List<ChangeLog> getChangeLogs() {
return changeLogs;
}

public void setChangeLogs(List<ChangeLog> changeLogs) {
this.changeLogs = changeLogs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.micronaut.data.document.mongodb.entities;

import io.micronaut.core.annotation.Introspected;
import org.bson.codecs.pojo.annotations.BsonId;
import org.bson.codecs.pojo.annotations.BsonRepresentation;

import static org.bson.BsonType.OBJECT_ID;

@Introspected
public record CustomerView(@BsonId @BsonRepresentation(OBJECT_ID) String id, String firstName, String lastName) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.micronaut.data.document.mongodb.repositories;

import io.micronaut.data.document.mongodb.entities.Customer;
import io.micronaut.data.document.mongodb.entities.CustomerView;
import io.micronaut.data.mongodb.annotation.MongoFindQuery;
import io.micronaut.data.mongodb.annotation.MongoRepository;
import io.micronaut.data.repository.CrudRepository;

import java.util.List;

@MongoRepository
public interface CustomerRepository extends CrudRepository<Customer, String> {

@MongoFindQuery(filter = "{}", project = "{ changeLogs: 0}")
List<CustomerView> viewFindAll();
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ class H2RepositorySpec extends AbstractRepositorySpec implements H2TestPropertyP
return context.getBean(H2EntityWithIdClass2Repository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(H2ExampleEntityRepository)
}

@Override
protected boolean skipQueryByDataArray() {
return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ class MariaDbRepositorySpec extends AbstractRepositorySpec implements MariaDbTes
return context.getBean(MySqlPageRepository)
}

@Memoized
@Override
ExampleEntityRepository getExampleEntityRepository() {
return context.getBean(MySqlExampleEntityRepository)
}

@Override
protected boolean skipCustomSchemaAndCatalogTest() {
// INSERT command denied to user 'test'@'172.17.0.1' for table 'cars'
Expand Down
Loading

0 comments on commit f874753

Please sign in to comment.