Skip to content

Commit 8c250c4

Browse files
Experiment with deriving storage document from lookup query.
1 parent a0b215f commit 8c250c4

File tree

2 files changed

+105
-16
lines changed

2 files changed

+105
-16
lines changed

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

+57-11
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,10 @@
1717

1818
import java.lang.reflect.Constructor;
1919
import java.lang.reflect.Method;
20-
import java.util.ArrayList;
21-
import java.util.Arrays;
22-
import java.util.Collection;
23-
import java.util.Collections;
24-
import java.util.HashSet;
25-
import java.util.LinkedHashMap;
26-
import java.util.List;
27-
import java.util.Map;
20+
import java.util.*;
2821
import java.util.Map.Entry;
29-
import java.util.Optional;
30-
import java.util.Set;
22+
import java.util.regex.Matcher;
23+
import java.util.regex.Pattern;
3124
import java.util.stream.Collectors;
3225

3326
import org.bson.Document;
@@ -52,6 +45,7 @@
5245
import org.springframework.data.mapping.PreferredConstructor.Parameter;
5346
import org.springframework.data.mapping.callback.EntityCallbacks;
5447
import org.springframework.data.mapping.context.MappingContext;
48+
import org.springframework.data.mapping.model.BeanWrapperPropertyAccessorFactory;
5549
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
5650
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
5751
import org.springframework.data.mapping.model.EntityInstantiator;
@@ -814,8 +808,60 @@ protected void writePropertyInternal(@Nullable Object obj, DocumentAccessor acce
814808
if (conversionService.canConvert(valueType.getType(), DocumentPointer.class)) {
815809
accessor.put(prop, conversionService.convert(obj, DocumentPointer.class).getPointer());
816810
} else {
811+
812+
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(prop.getAssociationTargetType());
813+
// TODO: Move this to helper for queries
814+
815+
816+
if(!prop.getDocumentReference().lookup().toLowerCase().replaceAll("\\s", "").replaceAll("'","").equals("{_id:?#{#target}}")) {
817+
818+
String lookup = prop.getDocumentReference().lookup();
819+
String targetLookup = lookup;
820+
821+
Pattern pattern = Pattern.compile("\\?#\\{#?[\\w\\d]*\\}");
822+
823+
Matcher matcher = pattern.matcher(lookup);
824+
int index = 0;
825+
Map<Integer, String> mapMap = new LinkedHashMap<>();
826+
while(matcher.find()) {
827+
828+
String expr = matcher.group();
829+
mapMap.put(Integer.valueOf(index), expr.substring(0, expr.length()-1).replace("?#{#", "").replace("?#{", "").replace("target.","").replaceAll("'",""));
830+
targetLookup = targetLookup.replace(expr, index + "");
831+
index++;
832+
}
833+
834+
Document fetchDocument = Document.parse(targetLookup);
835+
836+
PersistentPropertyAccessor<?> propertyAccessor = BeanWrapperPropertyAccessorFactory.INSTANCE.getPropertyAccessor(prop.getOwner(), obj);
837+
838+
839+
Document targetDocument = new Document();
840+
for(Entry<String, Object> entry : fetchDocument.entrySet()) {
841+
842+
if(entry.getKey().equals("target")) {
843+
844+
String refKey = mapMap.get(entry.getValue());
845+
846+
if(persistentEntity.hasIdProperty()) {
847+
targetDocument.put(refKey, persistentEntity.getIdentifierAccessor(obj).getIdentifier());
848+
} else {
849+
targetDocument.put(refKey, obj);
850+
}
851+
continue;
852+
}
853+
854+
Object value = propertyAccessor.getProperty(persistentEntity.getPersistentProperty(entry.getKey()));
855+
String refKey = mapMap.get(entry.getValue());
856+
targetDocument.put(refKey, value);
857+
}
858+
859+
accessor.put(prop, targetDocument);
860+
return;
861+
}
862+
817863
// just take the id as a reference
818-
accessor.put(prop, mappingContext.getPersistentEntity(prop.getAssociationTargetType())
864+
accessor.put(prop, persistentEntity
819865
.getIdentifierAccessor(obj).getIdentifier());
820866
}
821867
return;

Diff for: spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java

+48-5
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.junit.jupiter.api.extension.ExtendWith;
3939
import org.springframework.core.convert.converter.Converter;
4040
import org.springframework.data.annotation.Id;
41-
import org.springframework.data.annotation.PersistenceConstructor;
4241
import org.springframework.data.convert.WritingConverter;
4342
import org.springframework.data.mongodb.core.convert.LazyLoadingTestUtils;
4443
import org.springframework.data.mongodb.core.mapping.DocumentPointer;
@@ -807,16 +806,42 @@ void useReadingWriterConverterPairForLoading() {
807806
template.save(root);
808807

809808
Document target = template.execute(db -> {
810-
return db.getCollection(template.getCollectionName(SingleRefRoot.class))
811-
.find(Filters.eq("_id", root.id)).first();
809+
return db.getCollection(template.getCollectionName(SingleRefRoot.class)).find(Filters.eq("_id", root.id)).first();
812810
});
813811

814-
assertThat(target).containsEntry("withReadingConverter", new Document("ref-key-from-custom-write-converter", root.withReadingConverter.id));
812+
assertThat(target).containsEntry("withReadingConverter",
813+
new Document("ref-key-from-custom-write-converter", root.withReadingConverter.id));
815814

816815
SingleRefRoot loaded = template.findOne(query(where("id").is(root.id)), SingleRefRoot.class);
817816
assertThat(loaded.withReadingConverter).isInstanceOf(SimpleObjectRefWithReadingConverter.class);
818817
}
819818

819+
@Test // GH-3602
820+
void deriveMappingFromLookup() {
821+
822+
Publisher publisher = new Publisher();
823+
publisher.id = "p-1";
824+
publisher.acronym = "TOR";
825+
publisher.name = "Tom Doherty Associates";
826+
827+
template.save(publisher);
828+
829+
Book book = new Book();
830+
book.id = "book-1";
831+
book.publisher = publisher;
832+
833+
template.save(book);
834+
835+
Document target = template.execute(db -> {
836+
return db.getCollection(template.getCollectionName(Book.class)).find(Filters.eq("_id", book.id)).first();
837+
});
838+
839+
assertThat(target).containsEntry("publisher", new Document("acc", publisher.acronym).append("n", publisher.name));
840+
841+
Book result = template.findOne(query(where("id").is(book.id)), Book.class);
842+
assertThat(result.publisher).isNotNull();
843+
}
844+
820845
@Data
821846
static class SingleRefRoot {
822847

@@ -956,7 +981,8 @@ class DocumentToSimpleObjectRefWithReadingConverter
956981
@Override
957982
public SimpleObjectRefWithReadingConverter convert(DocumentPointer<Document> source) {
958983

959-
Document document = client.getDatabase(DB_NAME).getCollection("simple-object-ref").find(Filters.eq("_id", source.getPointer().get("ref-key-from-custom-write-converter"))).first();
984+
Document document = client.getDatabase(DB_NAME).getCollection("simple-object-ref")
985+
.find(Filters.eq("_id", source.getPointer().get("ref-key-from-custom-write-converter"))).first();
960986
return new SimpleObjectRefWithReadingConverter(document.getString("_id"), document.getString("value"));
961987
}
962988
}
@@ -1011,4 +1037,21 @@ public DocumentPointer<Document> convert(ReferencedObject source) {
10111037
return () -> new Document("", source);
10121038
}
10131039
}
1040+
1041+
@Data
1042+
static class Book {
1043+
1044+
String id;
1045+
1046+
@DocumentReference(lookup = "{ 'acronym' : ?#{acc}, 'name' : ?#{n} }") Publisher publisher;
1047+
1048+
}
1049+
1050+
static class Publisher {
1051+
1052+
String id;
1053+
String acronym;
1054+
String name;
1055+
}
1056+
10141057
}

0 commit comments

Comments
 (0)