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 fieldEnd; + private boolean not; + + public MorphiaTranslationContext(Query query) { + this.query = query; + } + + public FieldEnd pickFieldEnd() { + checkState(this.fieldEnd != null, "No field has been set"); + FieldEnd 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