Polishing.
Add tests for projections on dbref properties update java- and reference documentation. Original Pull Request: #3894
This commit is contained in:
@@ -245,8 +245,17 @@ class EntityOperations {
|
||||
return UntypedOperations.instance();
|
||||
}
|
||||
|
||||
public <M, D> EntityProjection<M, D> introspectProjection(Class<M> resultType,
|
||||
Class<D> entityType) {
|
||||
/**
|
||||
* Introspect the given {@link Class result type} in the context of the {@link Class entity type} whether the returned
|
||||
* type is a projection and what property paths are participating in the projection.
|
||||
*
|
||||
* @param resultType the type to project on. Must not be {@literal null}.
|
||||
* @param entityType the source domain type. Must not be {@literal null}.
|
||||
* @return the introspection result.
|
||||
* @since 3.4
|
||||
* @see EntityProjectionIntrospector#introspect(Class, Class)
|
||||
*/
|
||||
public <M, D> EntityProjection<M, D> introspectProjection(Class<M> resultType, Class<D> entityType) {
|
||||
return introspector.introspect(resultType, entityType);
|
||||
}
|
||||
|
||||
|
||||
@@ -2777,8 +2777,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
@Nullable
|
||||
private <T> T doFindAndReplace(String collectionName, Document mappedQuery, Document mappedFields,
|
||||
Document mappedSort, @Nullable com.mongodb.client.model.Collation collation, Class<?> entityType,
|
||||
Document replacement, FindAndReplaceOptions options,
|
||||
EntityProjection<T, ?> projection) {
|
||||
Document replacement, FindAndReplaceOptions options, EntityProjection<T, ?> projection) {
|
||||
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(String.format(
|
||||
@@ -3240,14 +3239,14 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
*/
|
||||
private class ProjectingReadCallback<S, T> implements DocumentCallback<T> {
|
||||
|
||||
private final MongoConverter reader;
|
||||
private final MongoConverter mongoConverter;
|
||||
private final EntityProjection<T, S> projection;
|
||||
private final String collectionName;
|
||||
|
||||
ProjectingReadCallback(MongoConverter reader, EntityProjection<T, S> projection,
|
||||
ProjectingReadCallback(MongoConverter mongoConverter, EntityProjection<T, S> projection,
|
||||
String collectionName) {
|
||||
|
||||
this.reader = reader;
|
||||
this.mongoConverter = mongoConverter;
|
||||
this.projection = projection;
|
||||
this.collectionName = collectionName;
|
||||
}
|
||||
@@ -3265,10 +3264,10 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware,
|
||||
|
||||
maybeEmitEvent(new AfterLoadEvent<>(document, projection.getMappedType().getType(), collectionName));
|
||||
|
||||
Object entity = reader.project(projection, document);
|
||||
Object entity = mongoConverter.project(projection, document);
|
||||
|
||||
if (entity == null) {
|
||||
throw new MappingException(String.format("EntityReader %s returned null", reader));
|
||||
throw new MappingException(String.format("EntityReader %s returned null", mongoConverter));
|
||||
}
|
||||
|
||||
maybeEmitEvent(new AfterConvertEvent<>(document, entity, collectionName));
|
||||
|
||||
@@ -51,7 +51,7 @@ class PropertyOperations {
|
||||
Document computeMappedFieldsForProjection(EntityProjection<?, ?> projection,
|
||||
Document fields) {
|
||||
|
||||
if (!projection.isProjection() || !projection.isClosedProjection()) {
|
||||
if (!projection.isClosedProjection()) {
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
@@ -2621,8 +2621,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
|
||||
*/
|
||||
private <T> Mono<T> doFindAndReplace(String collectionName, Document mappedQuery, Document mappedFields,
|
||||
Document mappedSort, com.mongodb.client.model.Collation collation, Class<?> entityType, Document replacement,
|
||||
FindAndReplaceOptions options,
|
||||
EntityProjection<T, ?> projection) {
|
||||
FindAndReplaceOptions options, EntityProjection<T, ?> projection) {
|
||||
|
||||
return Mono.defer(() -> {
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.bson.BsonString;
|
||||
import org.bson.BsonValue;
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@@ -44,6 +45,8 @@ import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.mongodb.core.ExecutableFindOperation.TerminatingFind;
|
||||
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
|
||||
import org.springframework.data.mongodb.core.index.GeospatialIndex;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.DocumentReference;
|
||||
import org.springframework.data.mongodb.core.mapping.Field;
|
||||
import org.springframework.data.mongodb.core.query.BasicQuery;
|
||||
import org.springframework.data.mongodb.core.query.NearQuery;
|
||||
@@ -549,6 +552,71 @@ class ExecutableFindOperationSupportTests {
|
||||
).containsExactlyInAnyOrder("luke");
|
||||
}
|
||||
|
||||
@Test // GH-2860
|
||||
void projectionOnDbRef() {
|
||||
|
||||
WithRefs source = new WithRefs();
|
||||
source.id = "id-1";
|
||||
source.noRef = "value";
|
||||
source.planetDbRef = alderan;
|
||||
|
||||
template.save(source);
|
||||
|
||||
WithDbRefProjection target = template.query(WithRefs.class).as(WithDbRefProjection.class)
|
||||
.matching(where("id").is(source.id)).oneValue();
|
||||
|
||||
assertThat(target.getPlanetDbRef()).isEqualTo(alderan);
|
||||
}
|
||||
|
||||
@Test // GH-2860
|
||||
@Disabled("GH-3913")
|
||||
void propertyProjectionOnDbRef() {
|
||||
|
||||
WithRefs source = new WithRefs();
|
||||
source.id = "id-1";
|
||||
source.noRef = "value";
|
||||
source.planetDbRef = alderan;
|
||||
|
||||
template.save(source);
|
||||
|
||||
WithDbRefPropertyProjection target = template.query(WithRefs.class).as(WithDbRefPropertyProjection.class)
|
||||
.matching(where("id").is(source.id)).oneValue();
|
||||
|
||||
assertThat(target.getPlanetDbRef().getName()).isEqualTo(alderan.getName());
|
||||
}
|
||||
|
||||
@Test // GH-2860
|
||||
void projectionOnDocRef() {
|
||||
|
||||
WithRefs source = new WithRefs();
|
||||
source.id = "id-1";
|
||||
source.noRef = "value";
|
||||
source.planetDocRef = alderan;
|
||||
|
||||
template.save(source);
|
||||
|
||||
WithDocumentRefProjection target = template.query(WithRefs.class).as(WithDocumentRefProjection.class)
|
||||
.matching(where("id").is(source.id)).oneValue();
|
||||
|
||||
assertThat(target.getPlanetDocRef()).isEqualTo(alderan);
|
||||
}
|
||||
|
||||
@Test // GH-2860
|
||||
void propertyProjectionOnDocRef() {
|
||||
|
||||
WithRefs source = new WithRefs();
|
||||
source.id = "id-1";
|
||||
source.noRef = "value";
|
||||
source.planetDocRef = alderan;
|
||||
|
||||
template.save(source);
|
||||
|
||||
WithDocRefPropertyProjection target = template.query(WithRefs.class).as(WithDocRefPropertyProjection.class)
|
||||
.matching(where("id").is(source.id)).oneValue();
|
||||
|
||||
assertThat(target.getPlanetDocRef().getName()).isEqualTo(alderan.getName());
|
||||
}
|
||||
|
||||
interface Contact {}
|
||||
|
||||
@Data
|
||||
@@ -618,6 +686,34 @@ class ExecutableFindOperationSupportTests {
|
||||
String getId();
|
||||
}
|
||||
|
||||
@Data
|
||||
static class WithRefs {
|
||||
|
||||
@Id String id;
|
||||
|
||||
String noRef;
|
||||
|
||||
@DBRef Planet planetDbRef;
|
||||
|
||||
@DocumentReference Planet planetDocRef;
|
||||
}
|
||||
|
||||
interface WithDbRefProjection {
|
||||
Planet getPlanetDbRef();
|
||||
}
|
||||
|
||||
interface WithDocumentRefProjection {
|
||||
Planet getPlanetDocRef();
|
||||
}
|
||||
|
||||
interface WithDbRefPropertyProjection {
|
||||
PlanetProjection getPlanetDbRef();
|
||||
}
|
||||
|
||||
interface WithDocRefPropertyProjection {
|
||||
PlanetProjection getPlanetDocRef();
|
||||
}
|
||||
|
||||
private void initPersons() {
|
||||
|
||||
han = new Person();
|
||||
|
||||
@@ -2050,6 +2050,8 @@ NOTE: Using projections allows `MongoTemplate` to optimize result mapping by lim
|
||||
by the projection target type. This applies as long as the `Query` itself does not contain any field restriction and the
|
||||
target type is a closed interface or DTO projection.
|
||||
|
||||
WARNING: Projections must not be applied to <<mapping-usage-references,DBRefs>>.
|
||||
|
||||
You can switch between retrieving a single entity and retrieving multiple entities as a `List` or a `Stream` through the terminating methods: `first()`, `one()`, `all()`, or `stream()`.
|
||||
|
||||
When writing a geo-spatial query with `near(NearQuery)`, the number of terminating methods is altered to include only the methods that are valid for running a `geoNear` command in MongoDB (fetching entities as a `GeoResult` within `GeoResults`), as the following example shows:
|
||||
|
||||
Reference in New Issue
Block a user