From c14c42fb0c77c87a01b7f1775c125b1ddabd4731 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 9 Mar 2016 16:56:59 +0100 Subject: [PATCH] DATAMONGO-1394 - Support identifier references on Querydsl expressions for DBRefs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now allow direct usage path.eq(…) on id properties of db referenced objects. This allows to write the query as person.coworker.id.eq(coworker.getId()) instead of person.coworker.eq(coworker). This helps building the query using just the plain id not having to actually create new object wrapping it. Original pull request: #373. --- .../support/SpringDataMongodbSerializer.java | 75 ++++++++++++++++++- .../QuerydslRepositorySupportTests.java | 32 +++++++- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializer.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializer.java index 6ee178bbb..9ca6ecec2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializer.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2015 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,9 @@ import org.springframework.util.Assert; import com.mongodb.DBObject; import com.mongodb.DBRef; +import com.querydsl.core.types.Constant; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.Operation; import com.querydsl.core.types.Path; import com.querydsl.core.types.PathMetadata; import com.querydsl.core.types.PathType; @@ -100,7 +103,6 @@ class SpringDataMongodbSerializer extends MongodbSerializer { if (ID_KEY.equals(key)) { return mapper.getMappedObject(super.asDBObject(key, value), null); } - return super.asDBObject(key, value instanceof Pattern ? value : converter.convertToMongoType(value)); } @@ -111,7 +113,7 @@ class SpringDataMongodbSerializer extends MongodbSerializer { @Override protected boolean isReference(Path path) { - MongoPersistentProperty property = getPropertyFor(path); + MongoPersistentProperty property = getPropertyForPotentialDbRef(path); return property == null ? false : property.isAssociation(); } @@ -121,7 +123,50 @@ class SpringDataMongodbSerializer extends MongodbSerializer { */ @Override protected DBRef asReference(Object constant) { - return converter.toDBRef(constant, null); + return asReference(constant, null); + } + + protected DBRef asReference(Object constant, Path path) { + return converter.toDBRef(constant, getPropertyForPotentialDbRef(path)); + } + + @Override + protected String asDBKey(Operation expr, int index) { + + Expression arg = expr.getArg(index); + if (arg instanceof Path) { + + Path path = (Path) arg; + if (isReference(path)) { + + MongoPersistentProperty property = getPropertyFor(path); + if (property.isIdProperty()) { + return super.asDBKey(expr, index).replaceAll("." + ID_KEY + "$", ""); + } + } + + } + return super.asDBKey(expr, index); + } + + /* + * (non-Javadoc) + * @see com.querydsl.mongodb.MongodbSerializer#convert(com.querydsl.core.types.Path, com.querydsl.core.types.Constant) + */ + protected Object convert(Path path, Constant constant) { + + if (isReference(path)) { + + MongoPersistentProperty property = getPropertyFor(path); + + if (property.isIdProperty()) { + return asReference(constant.getConstant(), path.getMetadata().getParent()); + } + + return asReference(constant.getConstant(), path); + } + + return super.convert(path, constant); } private MongoPersistentProperty getPropertyFor(Path path) { @@ -135,4 +180,26 @@ class SpringDataMongodbSerializer extends MongodbSerializer { MongoPersistentEntity entity = mappingContext.getPersistentEntity(parent.getType()); return entity != null ? entity.getPersistentProperty(path.getMetadata().getName()) : null; } + + /** + * Checks the given {@literal path} for referencing the {@literal id} property of a {@link DBRef} referenced object. + * If so it returns the referenced {@link MongoPersistentProperty} of the {@link DBRef} instead of the {@literal id} + * property. + * + * @param path + * @return + */ + private MongoPersistentProperty getPropertyForPotentialDbRef(Path path) { + + if (path == null) { + return null; + } + + MongoPersistentProperty property = getPropertyFor(path); + if (property != null && property.isIdProperty() && path.getMetadata() != null + && path.getMetadata().getParent() != null) { + return getPropertyFor(path.getMetadata().getParent()); + } + return property; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslRepositorySupportTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslRepositorySupportTests.java index ccb848cb3..dc275d5c9 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslRepositorySupportTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/QuerydslRepositorySupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.repository.Person; import org.springframework.data.mongodb.repository.QPerson; +import org.springframework.data.mongodb.repository.User; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -43,6 +44,7 @@ public class QuerydslRepositorySupportTests { @Autowired MongoOperations operations; Person person; + QuerydslRepositorySupport repoSupport; @Before public void setUp() { @@ -50,6 +52,8 @@ public class QuerydslRepositorySupportTests { operations.remove(new Query(), Person.class); person = new Person("Dave", "Matthews"); operations.save(person); + + repoSupport = new QuerydslRepositorySupport(operations) {}; } @Test @@ -72,10 +76,32 @@ public class QuerydslRepositorySupportTests { operations.save(person); QPerson p = QPerson.person; - QuerydslRepositorySupport support = new QuerydslRepositorySupport(operations) {}; - SpringDataMongodbQuery query = support.from(p).where(p.skills.any().in("guitarist")); + SpringDataMongodbQuery query = repoSupport.from(p).where(p.skills.any().in("guitarist")); assertThat(query.fetchOne(), is(person)); } + + /** + * @see DATAMONGO-1394 + */ + @Test + public void shouldAllowDbRefAgainstIdProperty() { + + User bart = new User(); + bart.setUsername("bart@simpson.com"); + operations.save(bart); + + person.setCoworker(bart); + operations.save(person); + + QPerson p = QPerson.person; + + SpringDataMongodbQuery queryUsingIdField = repoSupport.from(p).where(p.coworker.id.eq(bart.getId())); + SpringDataMongodbQuery queryUsingRefObject = repoSupport.from(p).where(p.coworker.eq(bart)); + + assertThat(queryUsingIdField.fetchOne(), equalTo(person)); + assertThat(queryUsingIdField.fetchOne(), equalTo(queryUsingRefObject.fetchOne())); + } + }