diff --git a/.travis.yml b/.travis.yml
index bc62848..bb79839 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,9 +12,9 @@ cache:
install:
- echo "bintray\${env.BINTRAY_USER}\${env.BINTRAY_KEY}" > ~/.m2/settings.xml
- - if [[ $TRAVIS_PULL_REQUEST = false ]] && [[ $TRAVIS_BRANCH = master ]] || [[ $TRAVIS_TAG = v* ]]; then GOAL=deploy; else GOAL=install; fi
+ - if [[ $TRAVIS_PULL_REQUEST = false ]] && [[ $TRAVIS_BRANCH = master || $TRAVIS_BRANCH = dev-* ]] || [[ $TRAVIS_TAG = v* ]]; then GOAL=deploy; else GOAL=install; fi
- if [[ $TRAVIS_TAG = v* ]]; then ADDITIONAL_PROFILES=release; mvn -q -U org.seedstack:seedstack-maven-plugin:release; else ADDITIONAL_PROFILES=snapshots; fi
-script: mvn -q -U -T 2 -Pbuild-number,compatibility,bintray,javadoc,$ADDITIONAL_PROFILES $GOAL jacoco:report
+script: mvn -q -U -Pbuild-number,compatibility,bintray,quality,javadoc,$ADDITIONAL_PROFILES $GOAL jacoco:report
after_success: mvn -q coveralls:report -DrepoToken=$COVERALLS_TOKEN
diff --git a/core/pom.xml b/core/pom.xml
index 5da5a8f..083129e 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -14,7 +14,7 @@
org.seedstack.addons.mongodb
mongodb
- 2.0.0-SNAPSHOT
+ 3.0.0-SNAPSHOT
mongodb-core
diff --git a/core/src/main/java/org/seedstack/mongodb/internal/AsyncMongoDbManager.java b/core/src/main/java/org/seedstack/mongodb/internal/AsyncMongoDbManager.java
index 4a8ecf2..97c2249 100644
--- a/core/src/main/java/org/seedstack/mongodb/internal/AsyncMongoDbManager.java
+++ b/core/src/main/java/org/seedstack/mongodb/internal/AsyncMongoDbManager.java
@@ -21,8 +21,8 @@
import org.bson.codecs.configuration.CodecRegistry;
import org.seedstack.coffig.BuilderSupplier;
import org.seedstack.coffig.Coffig;
-import org.seedstack.coffig.util.Utils;
import org.seedstack.mongodb.MongoDbConfig;
+import org.seedstack.shed.reflect.Classes;
import java.util.List;
import java.util.Optional;
@@ -63,7 +63,7 @@ private MongoClientSettings buildMongoClientSettings(MongoDbConfig.ClientConfig
// Apply global settings
Optional.ofNullable(allSettings.readPreference).ifPresent(settingsBuilder::readPreference);
Optional.ofNullable(allSettings.writeConcern).ifPresent(settingsBuilder::writeConcern);
- Optional.ofNullable(allSettings.codecRegistry).map(Utils::instantiateDefault).ifPresent(settingsBuilder::codecRegistry);
+ Optional.ofNullable(allSettings.codecRegistry).map(Classes::instantiateDefault).ifPresent(settingsBuilder::codecRegistry);
// Apply sub-settings
settingsBuilder.clusterSettings(allSettings.cluster.get().build());
diff --git a/morphia/pom.xml b/morphia/pom.xml
index de792c2..c3a10cd 100644
--- a/morphia/pom.xml
+++ b/morphia/pom.xml
@@ -14,7 +14,7 @@
org.seedstack.addons.mongodb
mongodb
- 2.0.0-SNAPSHOT
+ 3.0.0-SNAPSHOT
mongodb-morphia
@@ -40,6 +40,12 @@
org.mongodb.morphia
morphia-logging-slf4j
${morphia.version}
+
+
+ org.slf4j
+ slf4j-api
+
+
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaIT.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaIT.java
index e2c0411..2716b63 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaIT.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaIT.java
@@ -8,34 +8,114 @@
package org.seedstack.mongodb.morphia;
import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.ProvisionException;
+import com.google.inject.TypeLiteral;
+import com.google.inject.util.Types;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Key;
+import org.seedstack.business.domain.Repository;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy1;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy2;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy3;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy4;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy5;
+import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy6;
import org.seedstack.mongodb.morphia.fixtures.user.Address;
import org.seedstack.mongodb.morphia.fixtures.user.User;
+import org.seedstack.mongodb.morphia.internal.MorphiaErrorCode;
+import org.seedstack.seed.SeedException;
import org.seedstack.seed.it.AbstractSeedIT;
import javax.validation.ConstraintViolationException;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
public class MorphiaIT extends AbstractSeedIT {
@Inject
@MorphiaDatastore(clientName = "client1", dbName = "db")
private Datastore datastore;
+ @Inject
+ private Injector injector;
@Test
- public void datastore_test() {
+ public void datastoreAccess() {
User user = new User(1L, "Gerard", "menvuça", new Address("France", "78300", "Poissy", "avenue de l'europe", 1));
Key keyUser = datastore.save(user);
Assertions.assertThat(keyUser).isNotNull();
}
@Test(expected = ConstraintViolationException.class)
- public void validation_is_working() {
+ public void validationIsWorking() {
User user = new User(1L, null, "menvuça", new Address("France", "78300", "Poissy", "avenue de l'europe", 1));
datastore.save(user);
fail("should not have saved");
}
+
+ @Test
+ public void repositoryInjectionTestNoClientForAggregate() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy1.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.CLIENT_NAME_NOT_CONFIGURED).getMessage());
+ }
+ }
+
+ private com.google.inject.Key> getMorphiaRepositoryOf(Class entity) {
+ return com.google.inject.Key.get(TypeLiteral.get(Types.newParameterizedType(Repository.class, entity, Long.class)), Morphia.class);
+ }
+
+ @Test
+ public void repositoryInjectionTestNoDbNameForAggregate() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy2.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_DATABASE).getMessage());
+ }
+ }
+
+ @Test
+ public void repositoryInjectionTestNoMongoDbClient() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy3.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_CLIENT).getMessage());
+ }
+ }
+
+ @Test
+ public void repositoryInjectionTestNoMongoDbDatabase() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy4.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_DATABASE).getMessage());
+ }
+ }
+
+ @Test
+ public void repositoryInjectionTestNoMongodbForAggregate() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy5.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.PERSISTED_CLASS_NOT_CONFIGURED).getMessage());
+ }
+ }
+
+ @Test
+ public void repositoryInjectionAsyncClient() {
+ try {
+ injector.getInstance(getMorphiaRepositoryOf(Dummy6.class));
+ } catch (ProvisionException e) {
+ assertThat(e.getCause().getMessage())
+ .isEqualTo(SeedException.createNew(MorphiaErrorCode.ASYNC_CLIENT_NOT_SUPPORTED).getMessage());
+ }
+ }
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaRepositoryIT.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaRepositoryIT.java
index 8e9c377..8864f7c 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaRepositoryIT.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/MorphiaRepositoryIT.java
@@ -8,182 +8,87 @@
package org.seedstack.mongodb.morphia;
import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.ProvisionException;
-import com.google.inject.TypeLiteral;
-import com.google.inject.util.Types;
+import org.junit.Before;
import org.junit.Test;
-import org.mongodb.morphia.mapping.MappingException;
-import org.mongodb.morphia.query.UpdateException;
+import org.seedstack.business.domain.AggregateNotFoundException;
import org.seedstack.business.domain.Repository;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy1;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy2;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy3;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy4;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy5;
-import org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy6;
import org.seedstack.mongodb.morphia.fixtures.user.Address;
-import org.seedstack.mongodb.morphia.fixtures.user.EntityStringId;
import org.seedstack.mongodb.morphia.fixtures.user.User;
-import org.seedstack.mongodb.morphia.internal.MorphiaErrorCode;
-import org.seedstack.seed.SeedException;
import org.seedstack.seed.it.AbstractSeedIT;
+import java.util.Optional;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
public class MorphiaRepositoryIT extends AbstractSeedIT {
-
@Inject
@Morphia
private Repository userRepository;
- @Inject
- @Morphia
- private Repository entityStringIdRepository;
-
- @Inject
- private Injector injector;
-
- @Test
- public void repository_injection_test_no_client_for_aggregate() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy1.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.CLIENT_NAME_NOT_CONFIGURED).getMessage());
- }
- }
-
- private Key> getMorphiaRepositoryOf(Class entity) {
- return Key.get(TypeLiteral.get(Types.newParameterizedType(Repository.class, entity, Long.class)), Morphia.class);
- }
-
- @Test
- public void repository_injection_test_no_dbName_for_aggregate() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy2.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_DATABASE).getMessage());
- }
- }
-
- @Test
- public void repository_injection_test_no_mongoDb_client() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy3.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_CLIENT).getMessage());
- }
- }
-
- @Test
- public void repository_injection_test_no_mongoDb_database() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy4.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.UNKNOWN_DATABASE).getMessage());
- }
- }
-
- @Test
- public void repository_injection_test_no_mongodb_for_aggregate() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy5.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.PERSISTED_CLASS_NOT_CONFIGURED).getMessage());
- }
+ @Before
+ public void setUp() throws Exception {
+ userRepository.clear();
}
@Test
- public void repository_injection_async_client() {
- try {
- injector.getInstance(getMorphiaRepositoryOf(Dummy6.class));
- } catch (ProvisionException e) {
- assertThat(e.getCause().getMessage())
- .isEqualTo(SeedException.createNew(MorphiaErrorCode.ASYNC_CLIENT_NOT_SUPPORTED).getMessage());
- }
+ public void addAndGet() throws Exception {
+ User user1 = createUser(1L, "someFirstName", "someLastName");
+ userRepository.add(user1);
+ Optional loaded = userRepository.get(1L);
+ assertThat(loaded).isPresent();
+ assertThat(loaded.get().getName()).isEqualTo("someFirstName");
+ assertThat(loaded.get().getLastname()).isEqualTo("someLastName");
}
-
@Test
- public void mongodb_repository_test() {
- assertThat(userRepository).isNotNull();
- User user1 = getUser(1L, "N°", "1");
- userRepository.persist(user1);
- User user2 = userRepository.load(user1.getEntityId());
- assertThat(user1.getId()).isEqualTo(user2.getId());
- assertThat(user1.getEntityId()).isEqualTo(user2.getEntityId());
- userRepository.delete(user1);
- User user3 = userRepository.load(user1.getEntityId());
- assertThat(user3).isEqualTo(null);
- User user5 = getUser(2L, "N°", "2");
- userRepository.delete(user5);
- userRepository.persist(user5);
- User user6 = userRepository.load(user5.getEntityId());
- assertThat(user6.getId()).isEqualTo(user5.getId());
- userRepository.delete(user5);
- user6 = userRepository.load(user5.getEntityId());
- assertThat(user6).isEqualTo(null);
- userRepository.persist(user5);
- assertThat(userRepository.load(2L)).isNotEqualTo(null);
- }
-
- @Test(expected = MappingException.class)
- public void mongodb_repository_save_without_id() {
- EntityStringId saved = entityStringIdRepository.save(new EntityStringId(null));
- fail("should not have saved");
- }
-
- @Test(expected = UpdateException.class)
- public void mongodb_repository_save_with_inexistent_id() {
- userRepository.save(getUser(100L, "Robert", "SMITH"));
- fail("should not have saved");
+ public void addRemoveAndGet() throws Exception {
+ User user1 = createUser(1L, "someFirstName", "someLastName");
+ userRepository.add(user1);
+ assertThat(userRepository.get(1L)).isPresent();
+ userRepository.remove(user1);
+ assertThat(userRepository.get(1L)).isNotPresent();
}
@Test
- public void mongodb_repository_save() {
- userRepository.persist(getUser(200L, "Robert", "SMITH"));
- assertThat(userRepository.save(getUser(200L, "Jane", "SMITH")).getEntityId()).isEqualTo(200L);
+ public void update() {
+ userRepository.add(createUser(200L, "Robert", "SMITH"));
+ userRepository.update(createUser(200L, "Jane", "SMITH"));
+ assertThat(userRepository.get(200L).get().getName()).isEqualTo("Jane");
}
- @Test
- public void mongodb_repository_persist_load() {
- userRepository.persist(getUser(300L, "Robert", "SMITH"));
- assertThat(userRepository.load(300L).getEntityId()).isEqualTo(300L);
+ @Test(expected = AggregateNotFoundException.class)
+ public void updateNonExistent() {
+ userRepository.update(createUser(100L, "Robert", "SMITH"));
+ fail("should not have updated");
}
@Test
- public void mongodb_repository_clear() {
- userRepository.persist(getUser(400L, "Robert", "SMITH"));
- userRepository.persist(getUser(401L, "Jayne", "SMITH"));
- assertThat(userRepository.load(400L).getEntityId()).isEqualTo(400L);
- assertThat(userRepository.load(401L).getEntityId()).isEqualTo(401L);
+ public void clear() {
+ userRepository.add(createUser(400L, "Robert", "SMITH"));
+ userRepository.add(createUser(401L, "Jayne", "SMITH"));
+ assertThat(userRepository.get(400L)).isPresent();
+ assertThat(userRepository.get(401L)).isPresent();
userRepository.clear();
- assertThat(userRepository.load(400L)).isNull();
- assertThat(userRepository.load(401L)).isNull();
+ assertThat(userRepository.get(400L)).isNotPresent();
+ assertThat(userRepository.get(401L)).isNotPresent();
}
@Test
- public void mongodb_repository_exists() {
- userRepository.persist(getUser(300L, "Robert", "SMITH"));
- assertThat(userRepository.exists(300L)).isTrue();
- assertThat(userRepository.exists(3010L)).isFalse();
+ public void contains() {
+ userRepository.add(createUser(300L, "Robert", "SMITH"));
+ assertThat(userRepository.contains(300L)).isTrue();
+ assertThat(userRepository.contains(3010L)).isFalse();
}
@Test
- public void mongodb_repository_count() {
- userRepository.persist(getUser(300L, "Robert", "SMITH"));
- userRepository.persist(getUser(301L, "Roberta", "SMITH"));
- assertThat(userRepository.count()).isEqualTo(2);
+ public void size() {
+ userRepository.add(createUser(300L, "Robert", "SMITH"));
+ userRepository.add(createUser(301L, "Roberta", "SMITH"));
+ assertThat(userRepository.size()).isEqualTo(2);
}
- public User getUser(long id, String firstname, String lastName) {
+ private User createUser(long id, String firstname, String lastName) {
return new User(id, firstname, lastName, new Address("France", "75001", "Paris", "Champ Elysee avenue", 1));
}
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/SpecificationIT.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/SpecificationIT.java
new file mode 100644
index 0000000..df88ecc
--- /dev/null
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/SpecificationIT.java
@@ -0,0 +1,254 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.seedstack.business.domain.Repository;
+import org.seedstack.business.specification.dsl.SpecificationBuilder;
+import org.seedstack.mongodb.morphia.fixtures.product.Product;
+import org.seedstack.seed.it.SeedITRunner;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SeedITRunner.class)
+public class SpecificationIT {
+ @Inject
+ @Morphia
+ private Repository repository;
+ @Inject
+ private SpecificationBuilder specificationBuilder;
+ private final Product product1 = createProduct(1L, "product1", "picture1", 2d);
+ private final Product product2 = createProduct(2L, "product2", "picture2", 2d);
+ private final Product product3 = createProduct(3L, "product3", "picture3", 2d);
+ private final Product product4 = createProduct(4L, "product4", " picture4", 2d);
+ private final Product product5 = createProduct(5L, "product5", "picture4 ", 2d);
+ private final Product product6 = createProduct(6L, "product6", "picture5", 5d);
+
+ @Before
+ public void setUp() throws Exception {
+ repository.clear();
+ repository.add(product1);
+ repository.add(product2);
+ repository.add(product3);
+ repository.add(product4);
+ repository.add(product5);
+ repository.add(product6);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ repository.clear();
+ }
+
+ @Test
+ public void testTrue() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .all()
+ .build())
+ ).containsExactly(product1, product2, product3, product4, product5, product6);
+ }
+
+ @Test
+ public void testFalse() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .none()
+ .build())
+ ).isEmpty();
+ }
+
+ @Test
+ public void testIdentity() throws Exception {
+ assertThat(repository.get(specificationBuilder.ofAggregate(Product.class)
+ .identity().is(3L)
+ .build())
+ ).containsExactly(product3);
+ assertThat(repository.get(specificationBuilder.ofAggregate(Product.class)
+ .identity().isNot(3L)
+ .build())
+ ).containsExactly(product1, product2, product4, product5, product6);
+ }
+
+ @Test
+ public void testGreaterThan() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("id").greaterThan(3)
+ .build())
+ ).containsExactly(product4, product5, product6);
+ }
+
+ @Test
+ public void testLessThan() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("id").lessThan(3)
+ .build())
+ ).containsExactly(product1, product2);
+ }
+
+ @Test
+ public void testEquality() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("price").equalTo(2d)
+ .build())
+ ).containsExactly(product1, product2, product3, product4, product5);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("price").equalTo(5d)
+ .build())
+ ).containsExactly(product6);
+ }
+
+ @Test
+ public void testStringEquality() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture1")
+ .build())
+ ).containsExactly(product1);
+ }
+
+ @Test
+ public void testStringEqualityWithTrim() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture4")
+ .build())
+ ).isEmpty();
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture4").trimmingLead()
+ .build())
+ ).containsExactly(product4);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture4").trimmingTail()
+ .build())
+ ).containsExactly(product5);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture4").trimming()
+ .build())
+ ).containsExactly(product4, product5);
+ }
+
+ @Test
+ public void testStringEqualityIgnoringCase() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("PICTurE3")
+ .build())
+ ).isEmpty();
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("PICTurE3").ignoringCase()
+ .build())
+ ).containsExactly(product3);
+ }
+
+ @Test
+ public void testStringMatching() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("picture?")
+ .build())
+ ).containsExactly(product1, product2, product3, product6);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("picture*")
+ .build())
+ ).containsExactly(product1, product2, product3, product5, product6);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pict?re5")
+ .build())
+ ).containsExactly(product6);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pic*re5")
+ .build())
+ ).containsExactly(product6);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("?ict?re5")
+ .build())
+ ).containsExactly(product6);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("*cture5")
+ .build())
+ ).containsExactly(product6);
+ }
+
+ @Test
+ public void testStringMatchingWithTrim() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pict?re4")
+ .build())
+ ).isEmpty();
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pict?re4").trimmingLead()
+ .build())
+ ).containsExactly(product4);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pict?re4").trimmingTail()
+ .build())
+ ).containsExactly(product5);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("pict?re4").trimming()
+ .build())
+ ).containsExactly(product4, product5);
+ }
+
+ @Test
+ public void testStringMatchingIgnoringCase() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("PI*urE3")
+ .build())
+ ).isEmpty();
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").matching("PI*urE3").ignoringCase()
+ .build())
+ ).containsExactly(product3);
+ }
+
+ @Test
+ public void testNot() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").not().equalTo("picture2")
+ .build())
+ ).containsExactly(product1, product3, product4, product5, product6);
+ }
+
+ @Test
+ public void testOr() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture2")
+ .or()
+ .property("designation").equalTo("product3")
+ .or()
+ .property("designation").equalTo("product4")
+ .build())
+ ).containsExactly(product2, product3, product4);
+ }
+
+ @Test
+ public void testAnd() throws Exception {
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture2")
+ .and()
+ .property("designation").equalTo("product2")
+ .and()
+ .property("price").equalTo(2d)
+ .build())
+ ).containsExactly(product2);
+ assertThat(repository.get(specificationBuilder.of(Product.class)
+ .property("pictures.name").equalTo("picture3")
+ .and()
+ .property("designation").equalTo("product2")
+ .build())
+ ).isEmpty();
+ }
+
+ public Product createProduct(long id, String designation, String pictureUrl, double price) {
+ List pictures = new ArrayList<>();
+ pictures.add(pictureUrl);
+ return new Product(id, designation, "summary", "details", pictures, price);
+ }
+}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy1.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy1.java
index 88b6892..d66af4f 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy1.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy1.java
@@ -12,7 +12,7 @@
public class Dummy1 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy2.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy2.java
index 261d011..9acd302 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy2.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy2.java
@@ -12,7 +12,7 @@
public class Dummy2 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy3.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy3.java
index 8508d6e..4c4a39c 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy3.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy3.java
@@ -12,7 +12,7 @@
public class Dummy3 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy4.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy4.java
index 51780aa..7e4808b 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy4.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy4.java
@@ -12,7 +12,7 @@
public class Dummy4 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy5.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy5.java
index 33906be..4ba1689 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy5.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy5.java
@@ -12,7 +12,7 @@
public class Dummy5 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy6.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy6.java
index ed87007..16ddd11 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy6.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/dummyobject/Dummy6.java
@@ -12,7 +12,7 @@
public class Dummy6 extends BaseAggregateRoot {
@Override
- public Long getEntityId() {
+ public Long getId() {
return null;
}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Picture.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Picture.java
new file mode 100644
index 0000000..2cbabed
--- /dev/null
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Picture.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+/**
+ *
+ */
+package org.seedstack.mongodb.morphia.fixtures.product;
+
+import org.mongodb.morphia.annotations.Embedded;
+import org.seedstack.business.domain.BaseValueObject;
+
+@Embedded
+public class Picture extends BaseValueObject {
+ private String name;
+ private Long productId;
+
+ public Picture(String name, Long productId) {
+ super();
+ this.name = name;
+ this.productId = productId;
+ }
+
+
+ public Picture() {
+
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Product.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Product.java
new file mode 100644
index 0000000..9b33385
--- /dev/null
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/product/Product.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.fixtures.product;
+
+import org.mongodb.morphia.annotations.Entity;
+import org.mongodb.morphia.annotations.Id;
+import org.seedstack.business.domain.BaseAggregateRoot;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+public class Product extends BaseAggregateRoot {
+ @Id
+ private Long id;
+ private String designation;
+ private String summary;
+ private String details;
+ private List pictures;
+ private Double price;
+
+ public Product() {
+
+ }
+
+ public Product(long productId, String designation, String summary, String details, List pictures, Double price) {
+ id = productId;
+ setDesignation(designation);
+ setSummary(summary);
+ setDetails(details);
+ List pics = null;
+ if (pictures != null && !pictures.isEmpty()) {
+ pics = new ArrayList<>();
+ for (String picture : pictures) {
+ pics.add(new Picture(picture, productId));
+ }
+ }
+ setPictures(pics);
+ setPrice(price);
+ }
+
+ @Override
+ public Long getId() {
+ return id;
+ }
+
+ public String getDesignation() {
+ return designation;
+ }
+
+ public void setDesignation(String designation) {
+ this.designation = designation;
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+ public void setDetails(String details) {
+ this.details = details;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ public void setPrice(Double price) {
+ this.price = price;
+ }
+
+ public List getPictures() {
+ return pictures;
+ }
+
+ public void setPictures(List pictures) {
+ this.pictures = pictures;
+ }
+
+ @Override
+ public String toString() {
+ return "Product{" +
+ "id=" + id +
+ ", designation='" + designation + '\'' +
+ ", summary='" + summary + '\'' +
+ ", details='" + details + '\'' +
+ ", pictures=" + pictures +
+ ", price=" + price +
+ '}';
+ }
+}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/EntityStringId.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/EntityStringId.java
deleted file mode 100644
index 16ca9d9..0000000
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/EntityStringId.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * Copyright (c) 2013-2016, The SeedStack authors
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-package org.seedstack.mongodb.morphia.fixtures.user;
-
-import org.mongodb.morphia.annotations.Entity;
-import org.mongodb.morphia.annotations.Id;
-import org.seedstack.business.domain.AggregateRoot;
-
-@Entity
-public class EntityStringId implements AggregateRoot {
- @Id
- private String id;
-
- public EntityStringId() {
- }
-
- public EntityStringId(String id) {
- this.id = id;
- }
-
- @Override
- public String getEntityId() {
- return id;
- }
-}
diff --git a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/User.java b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/User.java
index cd82f20..1bf02d6 100644
--- a/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/User.java
+++ b/morphia/src/it/java/org/seedstack/mongodb/morphia/fixtures/user/User.java
@@ -15,8 +15,6 @@
@Entity
public class User implements AggregateRoot {
-
-
public User() {
}
@@ -37,12 +35,12 @@ public User(long id, String name, String lastName, Address address) {
private Address address;
-
- public long getId() {
+ @Override
+ public Long getId() {
return id;
}
- public void setId(long id) {
+ public void setId(Long id) {
this.id = id;
}
@@ -69,11 +67,4 @@ public Address getAddress() {
public void setAddress(Address address) {
this.address = address;
}
-
- @Override
- public Long getEntityId() {
- return id;
- }
-
-
}
diff --git a/morphia/src/it/resources/application.yaml b/morphia/src/it/resources/application.yaml
index 383ae1b..5e2bb63 100644
--- a/morphia/src/it/resources/application.yaml
+++ b/morphia/src/it/resources/application.yaml
@@ -14,6 +14,7 @@ mongoDb:
connectionsPerHost: 50
databases:
db1: db
+ business: business
client2:
async: true
hosts: localhost
@@ -42,27 +43,6 @@ classes:
Dummy6:
mongoDbClient: client2
mongoDbDatabase: db2
-
-
-#
-#[org.seedstack.mongodb.morphia.fixtures.user.*]
-#morphia.clientName = client1
-#morphia.dbName = db
-#
-#[org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy1]
-#morphia.dbName = db4
-#
-#[org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy2]
-#morphia.clientName = clien1
-#
-#[org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy3]
-#morphia.dbName = client7
-#morphia.dbName = db6
-#
-#[org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy4]
-#morphia.clientName = client1
-#morphia.dbName = db6
-#
-#[org.seedstack.mongodb.morphia.fixtures.dummyobject.Dummy6]
-#morphia.clientName = client2
-#morphia.dbName = db2
\ No newline at end of file
+ product:
+ mongoDbClient: client1
+ mongoDbDatabase: business
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/BaseMorphiaRepository.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/BaseMorphiaRepository.java
index 4eb3a02..71f4b27 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/BaseMorphiaRepository.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/BaseMorphiaRepository.java
@@ -7,33 +7,49 @@
*/
package org.seedstack.mongodb.morphia;
-import com.google.inject.Injector;
-import com.google.inject.Key;
import org.mongodb.morphia.Datastore;
+import org.mongodb.morphia.mapping.Mapper;
+import org.mongodb.morphia.query.CountOptions;
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.mongodb.morphia.query.Query;
+import org.seedstack.business.domain.AggregateExistsException;
+import org.seedstack.business.domain.AggregateNotFoundException;
import org.seedstack.business.domain.AggregateRoot;
import org.seedstack.business.domain.BaseRepository;
-import org.seedstack.mongodb.morphia.internal.MorphiaUtils;
-import org.seedstack.seed.Application;
+import org.seedstack.business.specification.Specification;
+import org.seedstack.business.spi.SpecificationTranslator;
+import org.seedstack.mongodb.morphia.internal.DatastoreFactory;
+import org.seedstack.mongodb.morphia.internal.specification.MorphiaTranslationContext;
import javax.inject.Inject;
+import java.util.Optional;
+import java.util.stream.Stream;
/**
* This class can serve as a base class for Morphia repositories. It provides methods for common CRUD operations as
* well as access to the data store through the {@link #getDatastore()} ()} protected method.
*
- * @param Aggregate root class
- * @param Key class
+ * @param Aggregate root class.
+ * @param Identifier class.
*/
-public abstract class BaseMorphiaRepository, K> extends BaseRepository {
+public abstract class BaseMorphiaRepository, ID> extends BaseRepository {
private Datastore datastore;
+ private SpecificationTranslator specificationTranslator;
public BaseMorphiaRepository() {
+
}
- public BaseMorphiaRepository(Class aggregateRootClass, Class kClass) {
+ public BaseMorphiaRepository(Class aggregateRootClass, Class kClass) {
super(aggregateRootClass, kClass);
}
+ @Inject
+ private void init(DatastoreFactory datastoreFactory, SpecificationTranslator specificationTranslator) {
+ this.datastore = datastoreFactory.createDatastore(getAggregateRootClass());
+ this.specificationTranslator = specificationTranslator;
+ }
+
/**
* Provides access to the Morphia data store for implementing custom data access methods.
*
@@ -43,49 +59,79 @@ protected Datastore getDatastore() {
return datastore;
}
- @Inject
- private void initDatastore(Application application, Injector injector) {
- datastore = injector.getInstance(Key.get(Datastore.class, MorphiaUtils.getMongoDatastore(application, getAggregateRootClass())));
+ @Override
+ public void add(A aggregate) throws AggregateExistsException {
+ datastore.save(aggregate);
}
@Override
- public A load(K id) {
- return datastore.get(getAggregateRootClass(), id);
+ public Stream get(Specification specification, Option... options) {
+ return buildQuery(specification).asList().stream();
}
@Override
- public void clear() {
- datastore.getCollection(getAggregateRootClass()).drop();
+ public Optional get(ID id) {
+ return Optional.ofNullable(datastore.get(getAggregateRootClass(), id));
}
@Override
- public void delete(K id) {
- datastore.delete(getAggregateRootClass(), id);
+ public boolean contains(Specification specification) {
+ return buildQuery(specification).count(new CountOptions().limit(1)) > 0;
}
@Override
- public void delete(A aggregate) {
- datastore.delete(aggregate);
+ public boolean contains(ID id) {
+ return datastore.find(getAggregateRootClass()).filter(Mapper.ID_KEY, id).count(new CountOptions().limit(1)) > 0;
}
@Override
- public void persist(A aggregate) {
- datastore.save(aggregate);
+ public long count(Specification specification) {
+ return buildQuery(specification).count();
}
@Override
- public A save(A aggregate) {
- datastore.merge(aggregate);
- return aggregate;
+ public long size() {
+ return datastore.getCount(getAggregateRootClass());
}
@Override
- public boolean exists(K id) {
- return load(id) != null;
+ public long remove(Specification specification) throws AggregateNotFoundException {
+ return datastore.delete(buildQuery(specification)).getN();
}
@Override
- public long count() {
- return datastore.getCount(getAggregateRootClass());
+ public void remove(ID id) throws AggregateNotFoundException {
+ checkExactlyOneAggregateRemoved(datastore.delete(getAggregateRootClass(), id).getN(), id);
+ }
+
+ private void checkExactlyOneAggregateRemoved(int n, ID id) {
+ if (n == 0) {
+ throw new AggregateNotFoundException("Non-existent aggregate " + getAggregateRootClass().getSimpleName() + " identified with " + id + " cannot be removed");
+ } else if (n > 1) {
+ throw new IllegalStateException("More than one aggregate " + getAggregateRootClass().getSimpleName() + " identified with " + id + " have been removed");
+ }
+ }
+
+ @Override
+ public void update(A aggregate) throws AggregateNotFoundException {
+ if (!contains(aggregate)) {
+ throw new AggregateNotFoundException("Non-existent aggregate " + getAggregateRootClass().getSimpleName() + " identified with " + aggregate.getId() + " cannot be updated");
+ }
+ datastore.merge(aggregate);
+ }
+
+ @Override
+ public void clear() {
+ datastore.getCollection(getAggregateRootClass()).drop();
+ datastore.getCollection(getAggregateRootClass()).dropIndexes();
+ }
+
+ private Query buildQuery(Specification specification) {
+ Query query = datastore.createQuery(getAggregateRootClass());
+ specificationTranslator.translate(
+ specification,
+ new MorphiaTranslationContext<>(query)
+ );
+ return query;
}
}
\ No newline at end of file
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreFactory.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreFactory.java
new file mode 100644
index 0000000..c73ea8b
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreFactory.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.name.Names;
+import com.mongodb.MongoClient;
+import org.mongodb.morphia.Datastore;
+import org.mongodb.morphia.Morphia;
+import org.seedstack.mongodb.morphia.MorphiaDatastore;
+import org.seedstack.seed.Application;
+
+import javax.inject.Inject;
+
+import static org.seedstack.mongodb.morphia.internal.MorphiaUtils.createDatastoreAnnotation;
+import static org.seedstack.mongodb.morphia.internal.MorphiaUtils.getMongoClientConfig;
+
+public class DatastoreFactory {
+ private final Application application;
+ private final Injector injector;
+ private final Morphia morphia;
+
+ @Inject
+ DatastoreFactory(Application application, Injector injector, Morphia morphia) {
+ this.application = application;
+ this.injector = injector;
+ this.morphia = morphia;
+ }
+
+ public Datastore createDatastore(Class> morphiaClass) {
+ MorphiaDatastore datastoreAnnotation = createDatastoreAnnotation(application, morphiaClass);
+ return createDatastore(datastoreAnnotation.clientName(), datastoreAnnotation.dbName());
+ }
+
+ public Datastore createDatastore(String clientName, String dbName) {
+ Datastore datastore = morphia.createDatastore(
+ injector.getInstance(Key.get(MongoClient.class, Names.named(clientName))),
+ MorphiaUtils.resolveDatabaseAlias(
+ getMongoClientConfig(application, clientName),
+ dbName
+ )
+ );
+ datastore.ensureIndexes(true);
+ datastore.ensureCaps();
+ return datastore;
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaDatastoreImpl.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreImpl.java
similarity index 86%
rename from morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaDatastoreImpl.java
rename to morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreImpl.java
index 057f0bd..28b4abc 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaDatastoreImpl.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreImpl.java
@@ -12,13 +12,12 @@
import java.io.Serializable;
import java.lang.annotation.Annotation;
-class MorphiaDatastoreImpl implements MorphiaDatastore, Serializable {
-
+class DatastoreImpl implements MorphiaDatastore, Serializable {
private static final long serialVersionUID = 3861460142806494075L;
- private String clientName;
- private String dbName;
+ private final String clientName;
+ private final String dbName;
- MorphiaDatastoreImpl(String clientName, String dbName) {
+ DatastoreImpl(String clientName, String dbName) {
this.clientName = clientName;
this.dbName = dbName;
}
@@ -52,7 +51,7 @@ public boolean equals(Object obj) {
return false;
if (!(obj instanceof MorphiaDatastore))
return false;
- MorphiaDatastoreImpl other = (MorphiaDatastoreImpl) obj;
+ DatastoreImpl other = (DatastoreImpl) obj;
if (clientName == null) {
if (other.clientName != null)
return false;
@@ -65,6 +64,4 @@ public boolean equals(Object obj) {
return false;
return true;
}
-
-
}
\ No newline at end of file
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreProvider.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreProvider.java
index 43b7481..1f8fe21 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreProvider.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DatastoreProvider.java
@@ -7,44 +7,23 @@
*/
package org.seedstack.mongodb.morphia.internal;
-import com.google.inject.Injector;
-import com.google.inject.Key;
import com.google.inject.Provider;
-import com.google.inject.name.Names;
-import com.mongodb.MongoClient;
import org.mongodb.morphia.Datastore;
-import org.mongodb.morphia.Morphia;
import org.seedstack.mongodb.morphia.MorphiaDatastore;
-import org.seedstack.seed.Application;
import javax.inject.Inject;
class DatastoreProvider implements Provider {
private final MorphiaDatastore morphiaDatastore;
- private final Morphia morphia;
@Inject
- private Injector injector;
- @Inject
- private Application application;
+ private DatastoreFactory datastoreFactory;
- DatastoreProvider(MorphiaDatastore morphiaDatastore, Morphia morphia) {
- super();
+ DatastoreProvider(MorphiaDatastore morphiaDatastore) {
this.morphiaDatastore = morphiaDatastore;
- this.morphia = morphia;
}
@Override
public Datastore get() {
- String resolvedDbName = MorphiaUtils.resolveDatabaseAlias(
- MorphiaUtils.getMongoClientConfig(application, morphiaDatastore.clientName()),
- morphiaDatastore.dbName()
- );
- Datastore datastore = morphia.createDatastore(
- injector.getInstance(Key.get(MongoClient.class, Names.named(morphiaDatastore.clientName()))),
- resolvedDbName
- );
- datastore.ensureIndexes(true);
- datastore.ensureCaps();
- return datastore;
+ return datastoreFactory.createDatastore(morphiaDatastore.clientName(), morphiaDatastore.dbName());
}
}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DefaultMorphiaRepository.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DefaultMorphiaRepository.java
index 385190a..9563ef7 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DefaultMorphiaRepository.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/DefaultMorphiaRepository.java
@@ -12,7 +12,6 @@
import org.seedstack.business.spi.GenericImplementation;
import org.seedstack.mongodb.morphia.BaseMorphiaRepository;
import org.seedstack.mongodb.morphia.Morphia;
-import org.seedstack.seed.Application;
import javax.inject.Inject;
@@ -33,7 +32,6 @@
@Morphia
@GenericImplementation
public class DefaultMorphiaRepository, KEY> extends BaseMorphiaRepository {
-
/**
* Constructs a DefaultMongodbRepository.
*
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaModule.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaModule.java
index 2cbc880..c4c4fd1 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaModule.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaModule.java
@@ -31,9 +31,11 @@ class MorphiaModule extends AbstractModule {
@Override
protected void configure() {
+ bind(Morphia.class).toInstance(morphia);
+ bind(DatastoreFactory.class);
if (morphiaDatastoresAnnotation != null && !morphiaDatastoresAnnotation.isEmpty()) {
for (MorphiaDatastore morphiaDatastore : morphiaDatastoresAnnotation) {
- DatastoreProvider datastoreProvider = new DatastoreProvider(morphiaDatastore, morphia);
+ DatastoreProvider datastoreProvider = new DatastoreProvider(morphiaDatastore);
requestInjection(datastoreProvider);
bind(Key.get(Datastore.class, morphiaDatastore)).toProvider(datastoreProvider).in(Scopes.SINGLETON);
}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaPlugin.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaPlugin.java
index 01d6743..b9f1a6b 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaPlugin.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaPlugin.java
@@ -12,7 +12,6 @@
import io.nuun.kernel.api.plugin.context.InitContext;
import io.nuun.kernel.api.plugin.request.ClasspathScanRequest;
import org.mongodb.morphia.Morphia;
-import org.seedstack.mongodb.internal.MongoDbPlugin;
import org.seedstack.mongodb.morphia.MorphiaDatastore;
import org.seedstack.seed.Application;
import org.seedstack.seed.core.SeedRuntime;
@@ -32,7 +31,6 @@ public class MorphiaPlugin extends AbstractSeedPlugin {
private static final Logger LOGGER = LoggerFactory.getLogger(MorphiaPlugin.class);
private final Collection morphiaDatastores = new HashSet<>();
private final Morphia morphia = new Morphia();
- private MongoDbPlugin mongoDbPlugin;
private ValidatorFactory validatorFactory;
@Override
@@ -68,7 +66,7 @@ public InitState initialize(InitContext initContext) {
if (morphiaScannedClasses != null && !morphiaScannedClasses.isEmpty()) {
morphia.map(new HashSet<>(morphiaScannedClasses));
for (Class> morphiaClass : morphiaScannedClasses) {
- MorphiaDatastore morphiaDatastore = MorphiaUtils.getMongoDatastore(application, morphiaClass);
+ MorphiaDatastore morphiaDatastore = MorphiaUtils.createDatastoreAnnotation(application, morphiaClass);
if (!morphiaDatastores.contains(morphiaDatastore)) {
morphiaDatastores.add(morphiaDatastore);
}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaUtils.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaUtils.java
index 0723171..4a17909 100644
--- a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaUtils.java
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/MorphiaUtils.java
@@ -17,7 +17,7 @@
public final class MorphiaUtils {
private MorphiaUtils() {
-
+ // no instantiation allowed
}
/**
@@ -27,7 +27,7 @@ private MorphiaUtils() {
* @param morphiaClass persistent morphia object
* @return MorphiaDatastore
*/
- public static MorphiaDatastore getMongoDatastore(Application application, Class> morphiaClass) {
+ static MorphiaDatastore createDatastoreAnnotation(Application application, Class> morphiaClass) {
ClassConfiguration> morphiaEntityConfiguration = application.getConfiguration(morphiaClass);
if (morphiaEntityConfiguration.isEmpty()) {
throw SeedException.createNew(MorphiaErrorCode.PERSISTED_CLASS_NOT_CONFIGURED)
@@ -48,7 +48,7 @@ public static MorphiaDatastore getMongoDatastore(Application application, Class<
checkMongoClient(getMongoClientConfig(application, clientName), morphiaClass, clientName, dbName);
- return new MorphiaDatastoreImpl(clientName, dbName);
+ return new DatastoreImpl(clientName, dbName);
}
/**
@@ -58,7 +58,7 @@ public static MorphiaDatastore getMongoDatastore(Application application, Class<
* @param dbName the name of the alias or the database.
* @return the resolved database name (may be the provided database name if no alias is defined).
*/
- public static String resolveDatabaseAlias(MongoDbConfig.ClientConfig clientConfig, String dbName) {
+ static String resolveDatabaseAlias(MongoDbConfig.ClientConfig clientConfig, String dbName) {
for (Map.Entry databaseEntry : clientConfig.getDatabases().entrySet()) {
if (dbName.equals(databaseEntry.getValue().getAlias())) {
return databaseEntry.getKey();
@@ -74,7 +74,7 @@ public static String resolveDatabaseAlias(MongoDbConfig.ClientConfig clientConfi
* @param clientName The name of the configured MongoDb client.
* @return the client configuration.
*/
- public static MongoDbConfig.ClientConfig getMongoClientConfig(Application application, String clientName) {
+ static MongoDbConfig.ClientConfig getMongoClientConfig(Application application, String clientName) {
MongoDbConfig.ClientConfig clientConfig = application.getConfiguration().get(MongoDbConfig.class).getClients().get(clientName);
if (clientConfig == null) {
throw SeedException.createNew(MorphiaErrorCode.UNKNOWN_CLIENT)
@@ -83,7 +83,7 @@ public static MongoDbConfig.ClientConfig getMongoClientConfig(Application applic
return clientConfig;
}
- private static void checkMongoClient(MongoDbConfig.ClientConfig clientConfig, Class> mappedClass, String clientName, String dbName) {
+ static void checkMongoClient(MongoDbConfig.ClientConfig clientConfig, Class> mappedClass, String clientName, String dbName) {
boolean async = clientConfig.isAsync();
if (async) {
throw SeedException.createNew(MorphiaErrorCode.ASYNC_CLIENT_NOT_SUPPORTED)
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAndConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAndConverter.java
new file mode 100644
index 0000000..94f263e
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAndConverter.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.AndSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+import java.util.Arrays;
+
+class MorphiaAndConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(AndSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ return context.getQuery().and(
+ Arrays.stream(specification.getSpecifications())
+ .map(spec -> translator.translate(spec, context))
+ .toArray(CriteriaContainer[]::new)
+ );
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAttributeConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAttributeConverter.java
new file mode 100644
index 0000000..8de6d2d
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaAttributeConverter.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.AttributeSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+class MorphiaAttributeConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(AttributeSpecification, ?> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ context.setFieldEnd(specification.getPath());
+ return translator.translate(specification.getValueSpecification(), context);
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaEqualConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaEqualConverter.java
new file mode 100644
index 0000000..36d478d
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaEqualConverter.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.EqualSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+
+class MorphiaEqualConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(EqualSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ if (specification.getExpectedValue() == null) {
+ return context.pickFieldEnd().doesNotExist();
+ } else {
+ // We avoid using equal() because Morphia optimizes it without operator ("someAttr": "someVal")
+ // Thus generating an invalid query when trying to negate it ("$not": "someVal")
+ return context.pickFieldEnd().not().notEqual(specification.getExpectedValue());
+ }
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaFalseConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaFalseConverter.java
new file mode 100644
index 0000000..eb06272
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaFalseConverter.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.mapping.Mapper;
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.FalseSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+
+class MorphiaFalseConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(FalseSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ // Always false
+ return context.getQuery().criteria(Mapper.ID_KEY).doesNotExist();
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaGreaterThanConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaGreaterThanConverter.java
new file mode 100644
index 0000000..d797b0b
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaGreaterThanConverter.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.GreaterThanSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+
+class MorphiaGreaterThanConverter> implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(GreaterThanSpecification specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ return context.pickFieldEnd().greaterThan(specification.getExpectedValue());
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaIdentityConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaIdentityConverter.java
new file mode 100644
index 0000000..f523e4a
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaIdentityConverter.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.mapping.Mapper;
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.IdentitySpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+class MorphiaIdentityConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(IdentitySpecification, ?> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ context.setFieldEnd(Mapper.ID_KEY);
+ // We avoid using equal() because Morphia optimizes it without operator ("someAttr": "someVal")
+ // Thus generating an invalid query when trying to negate it ("$not": "someVal")
+ return context.pickFieldEnd().not().notEqual(specification.getExpectedIdentifier());
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaLessThanConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaLessThanConverter.java
new file mode 100644
index 0000000..76e092a
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaLessThanConverter.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.LessThanSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+
+class MorphiaLessThanConverter> implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(LessThanSpecification specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ return context.pickFieldEnd().lessThan(specification.getExpectedValue());
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaNotConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaNotConverter.java
new file mode 100644
index 0000000..364ff4c
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaNotConverter.java
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.NotSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+class MorphiaNotConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(NotSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ context.not();
+ return translator.translate(specification.getSpecification(), context);
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaOrConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaOrConverter.java
new file mode 100644
index 0000000..c0b059e
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaOrConverter.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.OrSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+import java.util.Arrays;
+
+class MorphiaOrConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(OrSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ return context.getQuery().or(
+ Arrays.stream(specification.getSpecifications())
+ .map(spec -> translator.translate(spec, context))
+ .toArray(CriteriaContainer[]::new)
+ );
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaSpecificationTranslator.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaSpecificationTranslator.java
new file mode 100644
index 0000000..07a3c01
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaSpecificationTranslator.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.Specification;
+import org.seedstack.business.spi.BaseSpecificationTranslator;
+
+class MorphiaSpecificationTranslator extends BaseSpecificationTranslator {
+ @Override
+ public > CriteriaContainer translate(S specification, MorphiaTranslationContext query) {
+ return convert(specification, query);
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringConverter.java
new file mode 100644
index 0000000..c74c1c0
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringConverter.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.StringSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+import java.util.regex.Pattern;
+
+abstract class MorphiaStringConverter implements SpecificationConverter, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(S specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ if (specification.getExpectedString() == null) {
+ return context.pickFieldEnd().doesNotExist();
+ } else {
+ StringSpecification.Options options = specification.getOptions();
+ if (hasNoOption(options) && !isRegex()) {
+ // We avoid using equal() because Morphia optimizes it without operator ("someAttr": "someVal")
+ // Thus generating an invalid query when trying to negate it ("$not": "someVal")
+ return context.pickFieldEnd().not().notEqual(specification.getExpectedString());
+ } else {
+ return context.pickFieldEnd().equal(buildRegex(options, specification.getExpectedString()));
+ }
+
+ }
+ }
+
+ private Pattern buildRegex(StringSpecification.Options options, String expectedString) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("^");
+ if (options.isTrimmed() || options.isLeadTrimmed()) {
+ sb.append("\\s*");
+ }
+ sb.append(buildRegexMatchingPart(expectedString));
+ if (options.isTrimmed() || options.isTailTrimmed()) {
+ sb.append("\\s*");
+ }
+ sb.append("$");
+ return Pattern.compile(sb.toString(), options.isIgnoringCase() ? Pattern.CASE_INSENSITIVE : 0);
+ }
+
+ private boolean hasNoOption(StringSpecification.Options options) {
+ return !options.isLeadTrimmed() && !options.isTailTrimmed() && !options.isTrimmed() && !options.isIgnoringCase();
+ }
+
+ abstract String buildRegexMatchingPart(String value);
+
+ abstract boolean isRegex();
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringEqualConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringEqualConverter.java
new file mode 100644
index 0000000..6477c5d
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringEqualConverter.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.seedstack.business.specification.StringEqualSpecification;
+
+import java.util.regex.Pattern;
+
+
+class MorphiaStringEqualConverter extends MorphiaStringConverter {
+ @Override
+ String buildRegexMatchingPart(String value) {
+ return Pattern.quote(value);
+ }
+
+ @Override
+ boolean isRegex() {
+ return false;
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringMatchingConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringMatchingConverter.java
new file mode 100644
index 0000000..9807fb7
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaStringMatchingConverter.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.seedstack.business.specification.StringMatchingSpecification;
+
+
+class MorphiaStringMatchingConverter extends MorphiaStringConverter {
+ @Override
+ String buildRegexMatchingPart(String value) {
+ return value
+ .replace(StringMatchingSpecification.SINGLE_CHARACTER_WILDCARD, ".")
+ .replace(StringMatchingSpecification.MULTI_CHARACTER_WILDCARD, ".*");
+ }
+
+ @Override
+ boolean isRegex() {
+ return true;
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTranslationContext.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTranslationContext.java
new file mode 100644
index 0000000..a86b15d
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTranslationContext.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.mongodb.morphia.query.FieldEnd;
+import org.mongodb.morphia.query.Query;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class MorphiaTranslationContext {
+ private final Query query;
+ private FieldEnd extends CriteriaContainer> fieldEnd;
+ private boolean not;
+
+ public MorphiaTranslationContext(Query query) {
+ this.query = query;
+ }
+
+ public FieldEnd extends CriteriaContainer> pickFieldEnd() {
+ checkState(this.fieldEnd != null, "No field has been set");
+ FieldEnd extends CriteriaContainer> result = this.fieldEnd;
+ this.fieldEnd = null;
+ return result;
+ }
+
+ public void setFieldEnd(String property) {
+ checkState(this.fieldEnd == null, "A field is already set");
+ if (not) {
+ this.fieldEnd = query.criteria(property).not();
+ } else {
+ this.fieldEnd = query.criteria(property);
+ }
+ this.not = false;
+ }
+
+ public void not() {
+ not = !not;
+ }
+
+ public Query getQuery() {
+ return query;
+ }
+}
diff --git a/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTrueConverter.java b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTrueConverter.java
new file mode 100644
index 0000000..46f8bc3
--- /dev/null
+++ b/morphia/src/main/java/org/seedstack/mongodb/morphia/internal/specification/MorphiaTrueConverter.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2013-2016, The SeedStack authors
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.seedstack.mongodb.morphia.internal.specification;
+
+import org.mongodb.morphia.mapping.Mapper;
+import org.mongodb.morphia.query.CriteriaContainer;
+import org.seedstack.business.specification.TrueSpecification;
+import org.seedstack.business.spi.SpecificationConverter;
+import org.seedstack.business.spi.SpecificationTranslator;
+
+
+class MorphiaTrueConverter implements SpecificationConverter, MorphiaTranslationContext>, CriteriaContainer> {
+ @Override
+ public CriteriaContainer convert(TrueSpecification> specification, MorphiaTranslationContext> context, SpecificationTranslator, CriteriaContainer> translator) {
+ // Always true
+ return context.getQuery().criteria(Mapper.ID_KEY).not().doesNotExist();
+ }
+}
diff --git a/morphia/src/test/resources/logback-test.xml b/morphia/src/test/resources/logback-test.xml
deleted file mode 100644
index 06dda42..0000000
--- a/morphia/src/test/resources/logback-test.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 96953d7..a272bef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,19 +14,19 @@
org.seedstack.poms
parent-internal
- 3.0.0
+ 3.1.0
org.seedstack.addons.mongodb
mongodb
- 2.0.0-SNAPSHOT
+ 3.0.0-SNAPSHOT
pom
- 3.0.1
+ 3.3.2-SNAPSHOT
3.0.3
- 1.1.1
- 3.0.1
+ 1.3.2
+ 4.0.0-SNAPSHOT
true