diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java index 740e636..fccfb13 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactory.java @@ -22,6 +22,7 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; import org.springframework.data.r2dbc.repository.R2dbcRepository; import org.springframework.data.r2dbc.repository.query.R2dbcQueryMethod; @@ -92,8 +93,8 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport { RelationalEntityInformation entityInformation = getEntityInformation(information.getDomainType(), information); - return getTargetRepositoryViaReflection(information, entityInformation, this.databaseClient, this.converter, - this.dataAccessStrategy); + return getTargetRepositoryViaReflection(information, entityInformation, + new R2dbcEntityTemplate(this.databaseClient, this.dataAccessStrategy), this.converter); } /* diff --git a/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java b/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java index 3693e67..191152e 100644 --- a/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java +++ b/src/main/java/org/springframework/data/r2dbc/repository/support/SimpleR2dbcRepository.java @@ -18,17 +18,15 @@ package org.springframework.data.r2dbc.repository.support; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.List; - import org.reactivestreams.Publisher; -import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.core.DatabaseClient; -import org.springframework.data.r2dbc.core.PreparedOperation; +import org.springframework.data.r2dbc.core.R2dbcEntityOperations; +import org.springframework.data.r2dbc.core.R2dbcEntityTemplate; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; -import org.springframework.data.r2dbc.core.StatementMapper; import org.springframework.data.r2dbc.query.Criteria; +import org.springframework.data.r2dbc.query.Query; import org.springframework.data.relational.core.mapping.RelationalPersistentProperty; import org.springframework.data.relational.core.sql.Functions; import org.springframework.data.relational.core.sql.Select; @@ -38,6 +36,7 @@ import org.springframework.data.relational.core.sql.Table; import org.springframework.data.relational.core.sql.render.SqlRenderer; import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.repository.reactive.ReactiveCrudRepository; +import org.springframework.data.util.Lazy; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -51,16 +50,45 @@ import org.springframework.util.Assert; public class SimpleR2dbcRepository implements ReactiveCrudRepository { private final RelationalEntityInformation entity; - private final DatabaseClient databaseClient; - private final R2dbcConverter converter; - private final ReactiveDataAccessStrategy accessStrategy; + private final R2dbcEntityOperations entityOperations; + private final Lazy idProperty; + /** + * Create a new {@link SimpleR2dbcRepository}. + * + * @param entity + * @param entityOperations + * @param converter + * @since 1.1 + */ + SimpleR2dbcRepository(RelationalEntityInformation entity, R2dbcEntityOperations entityOperations, + R2dbcConverter converter) { + + this.entity = entity; + this.entityOperations = entityOperations; + this.idProperty = Lazy.of(() -> converter // + .getMappingContext() // + .getRequiredPersistentEntity(this.entity.getJavaType()) // + .getRequiredIdProperty()); + } + + /** + * Create a new {@link SimpleR2dbcRepository}. + * + * @param entity + * @param databaseClient + * @param converter + * @param accessStrategy + */ public SimpleR2dbcRepository(RelationalEntityInformation entity, DatabaseClient databaseClient, R2dbcConverter converter, ReactiveDataAccessStrategy accessStrategy) { + this.entity = entity; - this.databaseClient = databaseClient; - this.converter = converter; - this.accessStrategy = accessStrategy; + this.entityOperations = new R2dbcEntityTemplate(databaseClient); + this.idProperty = Lazy.of(() -> converter // + .getMappingContext() // + .getRequiredPersistentEntity(this.entity.getJavaType()) // + .getRequiredIdProperty()); } /* (non-Javadoc) @@ -73,28 +101,10 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository { - - if (rowsUpdated == 0) { - sink.error(new TransientDataAccessResourceException( - String.format("Failed to update table [%s]. Row with Id [%s] does not exist.", - this.entity.getTableName(), this.entity.getId(objectToSave)))); - } else { - sink.next(objectToSave); - } - }); + return this.entityOperations.update(objectToSave); } /* (non-Javadoc) @@ -129,20 +139,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository columns = this.accessStrategy.getAllColumns(this.entity.getJavaType()); - String idProperty = getIdProperty().getName(); - - StatementMapper mapper = this.accessStrategy.getStatementMapper().forType(this.entity.getJavaType()); - StatementMapper.SelectSpec selectSpec = mapper.createSelect(this.entity.getTableName()) // - .withProjection(columns) // - .withCriteria(Criteria.where(idProperty).is(id)); - - PreparedOperation operation = mapper.getMappedObject(selectSpec); - - return this.databaseClient.execute(operation) // - .as(this.entity.getJavaType()) // - .fetch() // - .one(); + return this.entityOperations.selectOne(getIdQuery(id), this.entity.getJavaType()); } /* (non-Javadoc) @@ -161,18 +158,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository operation = mapper.getMappedObject(selectSpec); - - return this.databaseClient.execute(operation) // - .map((r, md) -> r) // - .first() // - .hasElement(); + return this.entityOperations.exists(getIdQuery(id), this.entity.getJavaType()); } /* (non-Javadoc) @@ -188,7 +174,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository findAll() { - return this.databaseClient.select().from(this.entity.getJavaType()).fetch().all(); + return this.entityOperations.select(Query.empty(), this.entity.getJavaType()); } /* (non-Javadoc) @@ -216,17 +202,9 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository columns = this.accessStrategy.getAllColumns(this.entity.getJavaType()); String idProperty = getIdProperty().getName(); - StatementMapper mapper = this.accessStrategy.getStatementMapper().forType(this.entity.getJavaType()); - StatementMapper.SelectSpec selectSpec = mapper.createSelect(this.entity.getTableName()) // - .withProjection(columns) // - .withCriteria(Criteria.where(idProperty).in(ids)); - - PreparedOperation operation = mapper.getMappedObject(selectSpec); - - return this.databaseClient.execute(operation).as(this.entity.getJavaType()).fetch().all(); + return this.entityOperations.select(Query.query(Criteria.where(idProperty).in(ids)), this.entity.getJavaType()); }); } @@ -235,17 +213,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository count() { - - Table table = Table.create(this.accessStrategy.toSql(this.entity.getTableName())); - Select select = StatementBuilder // - .select(Functions.count(table.column(this.accessStrategy.toSql(getIdProperty().getColumnName())))) // - .from(table) // - .build(); - - return this.databaseClient.execute(SqlRenderer.toString(select)) // - .map((r, md) -> r.get(0, Long.class)) // - .first() // - .defaultIfEmpty(0L); + return this.entityOperations.count(Query.empty(), this.entity.getJavaType()); } /* (non-Javadoc) @@ -257,13 +225,7 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository implements ReactiveCrudRepository deleteById(Publisher idPublisher) { Assert.notNull(idPublisher, "The Id Publisher must not be null!"); - StatementMapper statementMapper = this.accessStrategy.getStatementMapper().forType(this.entity.getJavaType()); return Flux.from(idPublisher).buffer().filter(ids -> !ids.isEmpty()).concatMap(ids -> { @@ -282,12 +243,9 @@ public class SimpleR2dbcRepository implements ReactiveCrudRepository implements ReactiveCrudRepository deleteAll() { - return this.databaseClient.delete().from(this.entity.getTableName()).then(); + return this.entityOperations.delete(Query.empty(), this.entity.getJavaType()).then(); } private RelationalPersistentProperty getIdProperty() { + return this.idProperty.get(); + } - return this.converter // - .getMappingContext() // - .getRequiredPersistentEntity(this.entity.getJavaType()) // - .getRequiredIdProperty(); + private Query getIdQuery(Object id) { + return Query.query(Criteria.where(getIdProperty().getName()).is(id)); } } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryUnitTests.java b/src/test/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryUnitTests.java index b18cc5b..dea67ea 100644 --- a/src/test/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/repository/support/R2dbcRepositoryFactoryUnitTests.java @@ -24,11 +24,12 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.data.mapping.context.MappingContext; +import org.springframework.data.annotation.Id; +import org.springframework.data.r2dbc.convert.MappingR2dbcConverter; import org.springframework.data.r2dbc.convert.R2dbcConverter; import org.springframework.data.r2dbc.core.DatabaseClient; import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy; -import org.springframework.data.relational.core.mapping.RelationalPersistentEntity; +import org.springframework.data.r2dbc.mapping.R2dbcMappingContext; import org.springframework.data.relational.repository.query.RelationalEntityInformation; import org.springframework.data.relational.repository.support.MappingRelationalEntityInformation; import org.springframework.data.repository.Repository; @@ -41,18 +42,15 @@ import org.springframework.data.repository.Repository; @RunWith(MockitoJUnitRunner.class) public class R2dbcRepositoryFactoryUnitTests { + R2dbcConverter r2dbcConverter = new MappingR2dbcConverter(new R2dbcMappingContext()); + @Mock DatabaseClient databaseClient; - @Mock R2dbcConverter r2dbcConverter; @Mock ReactiveDataAccessStrategy dataAccessStrategy; - @Mock @SuppressWarnings("rawtypes") MappingContext mappingContext; - @Mock @SuppressWarnings("rawtypes") RelationalPersistentEntity entity; @Before @SuppressWarnings("unchecked") public void before() { - when(mappingContext.getRequiredPersistentEntity(Person.class)).thenReturn(entity); when(dataAccessStrategy.getConverter()).thenReturn(r2dbcConverter); - when(r2dbcConverter.getMappingContext()).thenReturn(mappingContext); } @Test @@ -75,5 +73,7 @@ public class R2dbcRepositoryFactoryUnitTests { interface MyPersonRepository extends Repository {} - static class Person {} + static class Person { + @Id long id; + } }