diff --git a/mongodb/aggregation/pom.xml b/mongodb/aggregation/pom.xml index 7f45c01b0..c585a0651 100644 --- a/mongodb/aggregation/pom.xml +++ b/mongodb/aggregation/pom.xml @@ -12,4 +12,18 @@ 2.0.0.BUILD-SNAPSHOT - \ No newline at end of file + + + org.testcontainers + mongodb + 1.15.0-rc1 + test + + + org.testcontainers + junit-jupiter + 1.15.0-rc1 + test + + + diff --git a/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/Score.java b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/Score.java new file mode 100644 index 000000000..b7ec408da --- /dev/null +++ b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/Score.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.mongodb.aggregationupdate; + +import java.util.List; + +import org.springframework.data.mongodb.core.mapping.Document; + +/** + * @author Christoph Strobl + */ +@Document("scores") +class Score { + + private final Integer id; + private final String student; + private final List homework; + private final List quiz; + private final Integer extraCredit; + + Score(Integer id, String student, List homework, List quiz, Integer extraCredit) { + + this.id = id; + this.student = student; + this.homework = homework; + this.quiz = quiz; + this.extraCredit = extraCredit; + } +} diff --git a/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepository.java b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepository.java new file mode 100644 index 000000000..62fb100eb --- /dev/null +++ b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2020. the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.mongodb.aggregationupdate; + +import org.springframework.data.repository.CrudRepository; + +/** + * @author Christoph Strobl + */ +interface ScoreRepository extends CrudRepository, ScoreRepositoryCustom { + +} diff --git a/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustom.java b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustom.java new file mode 100644 index 000000000..ff90d6db0 --- /dev/null +++ b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustom.java @@ -0,0 +1,25 @@ +/* + * Copyright 2020. the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.mongodb.aggregationupdate; + +/** + * @author Christoph Strobl + */ +public interface ScoreRepositoryCustom { + + void calculateTotalScore(); + +} diff --git a/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustomImpl.java b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustomImpl.java new file mode 100644 index 000000000..6aae676eb --- /dev/null +++ b/mongodb/aggregation/src/main/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryCustomImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.mongodb.aggregationupdate; + +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.aggregation.AggregationUpdate; +import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators; +import org.springframework.data.mongodb.core.aggregation.SetOperation; +import org.springframework.stereotype.Component; + +/** + * @author Christoph Strobl + */ +@Component +class ScoreRepositoryCustomImpl implements ScoreRepositoryCustom { + + private final MongoOperations mongoOperations; + + ScoreRepositoryCustomImpl(MongoOperations mongoOperations) { + this.mongoOperations = mongoOperations; + } + + @Override + public void calculateTotalScore() { + + AggregationUpdate update = AggregationUpdate.update().set(SetOperation.builder() // + .set("totalHomework").toValueOf(ArithmeticOperators.valueOf("homework").sum()).and() // + .set("totalQuiz").toValueOf(ArithmeticOperators.valueOf("quiz").sum())) // + .set(SetOperation.builder() // + .set("totalScore") + .toValueOf(ArithmeticOperators.valueOf("totalHomework").add("totalQuiz").add("extraCredit"))); + + mongoOperations.update(Score.class).apply(update).all(); + } +} diff --git a/mongodb/aggregation/src/test/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryTests.java b/mongodb/aggregation/src/test/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryTests.java new file mode 100644 index 000000000..74b8dd863 --- /dev/null +++ b/mongodb/aggregation/src/test/java/example/springdata/mongodb/aggregationupdate/ScoreRepositoryTests.java @@ -0,0 +1,99 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example.springdata.mongodb.aggregationupdate; + +import static org.assertj.core.api.Assertions.*; + +import java.util.ArrayList; +import java.util.Arrays; + +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings.Builder; +import com.mongodb.client.MongoCollection; + +/** + * @author Christoph Strobl + * @since 2020/08 + */ +@ExtendWith(SpringExtension.class) +@Testcontainers +class ScoreRepositoryTests { + + @Container private static final MongoDBContainer MONGO_DB_CONTAINER = new MongoDBContainer( + DockerImageName.parse("mongo:4.2.8")); + + @Autowired MongoOperations operations; + @Autowired ScoreRepository repository; + + @Configuration + @EnableMongoRepositories + static class Config extends AbstractMongoClientConfiguration { + + @Override + protected String getDatabaseName() { + return "test"; + } + + @Override + protected void configureClientSettings(Builder builder) { + builder.applyConnectionString(new ConnectionString(MONGO_DB_CONTAINER.getReplicaSetUrl())); + } + } + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeEach() throws Exception { + + repository.deleteAll(); + + Score score1 = new Score(1, "Maya", Arrays.asList(10, 5, 10), Arrays.asList(10, 8), 0); + Score score2 = new Score(2, "Ryan", Arrays.asList(5, 6, 5), Arrays.asList(8, 8), 8); + + repository.saveAll(Arrays.asList(score1, score2)); + } + + @Test + void testAggregationUpdate() { + + repository.calculateTotalScore(); + + assertThat(nativeConnection(Score.class).find(new org.bson.Document()).into(new ArrayList<>())) + .containsExactlyInAnyOrder( // + org.bson.Document.parse( + "{\"_id\" : 1, \"student\" : \"Maya\", \"homework\" : [ 10, 5, 10 ], \"quiz\" : [ 10, 8 ], \"extraCredit\" : 0, \"totalHomework\" : 25, \"totalQuiz\" : 18, \"totalScore\" : 43, \"_class\" : \"example.springdata.mongodb.aggregationupdate.Score\"}"), + org.bson.Document.parse( + "{ \"_id\" : 2, \"student\" : \"Ryan\", \"homework\" : [ 5, 6, 5 ], \"quiz\" : [ 8, 8 ], \"extraCredit\" : 8, \"totalHomework\" : 16, \"totalQuiz\" : 16, \"totalScore\" : 40, \"_class\" : \"example.springdata.mongodb.aggregationupdate.Score\"}")); + } + + private MongoCollection nativeConnection(Class type) { + return operations.getCollection(operations.getCollectionName(type)); + } +}