Skip to content

Commit

Permalink
Add backoffice courses repository cache
Browse files Browse the repository at this point in the history
  • Loading branch information
rgomezcasas committed Nov 25, 2019
1 parent ea63495 commit 9c6a54f
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 2 deletions.
4 changes: 2 additions & 2 deletions apps/test/tv/codely/apps/ApplicationTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ protected void assertResponse(
String expectedResponse
) throws Exception {
ResultMatcher response = expectedResponse.isEmpty()
? content().string("")
: content().json(expectedResponse);
? content().string("")
: content().json(expectedResponse);

mockMvc
.perform(get(endpoint))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tv.codely.backoffice.courses.infrastructure.persistence;

import tv.codely.backoffice.courses.domain.BackofficeCourse;
import tv.codely.backoffice.courses.domain.BackofficeCourseRepository;
import tv.codely.shared.domain.criteria.Criteria;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public final class InMemoryCacheBackofficeCourseRepository implements BackofficeCourseRepository {
private final BackofficeCourseRepository repository;
private List<BackofficeCourse> courses = new ArrayList<>();
private HashMap<String, List<BackofficeCourse>> matchingCourses = new HashMap<>();

public InMemoryCacheBackofficeCourseRepository(BackofficeCourseRepository repository) {
this.repository = repository;
}

@Override
public void save(BackofficeCourse course) {
repository.save(course);
}

@Override
public List<BackofficeCourse> searchAll() {
return courses.isEmpty() ? searchAndFillCache() : courses;
}

@Override
public List<BackofficeCourse> matching(Criteria criteria) {
return matchingCourses.containsKey(criteria.serialize())
? matchingCourses.get(criteria.serialize())
: searchMatchingAndFillCache(criteria);
}

private List<BackofficeCourse> searchMatchingAndFillCache(Criteria criteria) {
List<BackofficeCourse> courses = repository.matching(criteria);

this.matchingCourses.put(criteria.serialize(), courses);

return courses;
}

private List<BackofficeCourse> searchAndFillCache() {
List<BackofficeCourse> courses = repository.searchAll();

this.courses = courses;

return courses;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package tv.codely.backoffice.courses.infrastructure.persistence;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import tv.codely.backoffice.BackofficeContextInfrastructureTestCase;
import tv.codely.backoffice.courses.domain.BackofficeCourse;
import tv.codely.backoffice.courses.domain.BackofficeCourseCriteriaMother;
import tv.codely.backoffice.courses.domain.BackofficeCourseMother;
import tv.codely.backoffice.courses.domain.BackofficeCourseRepository;
import tv.codely.shared.domain.criteria.Criteria;

import java.util.Arrays;
import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.mockito.Mockito.*;

final class InMemoryCacheBackofficeCourseRepositoryShould extends BackofficeContextInfrastructureTestCase {
private InMemoryCacheBackofficeCourseRepository repository;
private BackofficeCourseRepository innerRepository;

@BeforeEach
protected void setUp() {
innerRepository = mock(BackofficeCourseRepository.class);
repository = new InMemoryCacheBackofficeCourseRepository(innerRepository);
}

@Test
void save_a_course() {
BackofficeCourse course = BackofficeCourseMother.random();

repository.save(course);

shouldHaveSaved(course);
}

@Test
void search_all_existing_courses() {
BackofficeCourse course = BackofficeCourseMother.random();
BackofficeCourse anotherCourse = BackofficeCourseMother.random();
List<BackofficeCourse> courses = Arrays.asList(course, anotherCourse);

shouldSearchAll(courses);

assertThat(courses, containsInAnyOrder(repository.searchAll().toArray()));
}

@Test
void search_all_existing_courses_without_hitting_the_inner_repository_the_second_time() {
BackofficeCourse course = BackofficeCourseMother.random();
BackofficeCourse anotherCourse = BackofficeCourseMother.random();
List<BackofficeCourse> courses = Arrays.asList(course, anotherCourse);

shouldSearchAll(courses);

assertThat(courses, containsInAnyOrder(repository.searchAll().toArray()));
assertThat(courses, containsInAnyOrder(repository.searchAll().toArray()));
}

@Test
void search_courses_using_a_criteria() {
BackofficeCourse matchingCourse = BackofficeCourseMother.create("DDD en Java", "3 days");
BackofficeCourse anotherMatchingCourse = BackofficeCourseMother.create("DDD en TypeScript", "2.5 days");
List<BackofficeCourse> matchingCourses = Arrays.asList(matchingCourse, anotherMatchingCourse);

Criteria criteria = BackofficeCourseCriteriaMother.nameAndDurationContains("DDD", "days");

shouldSearchMatching(criteria, matchingCourses);

assertThat(matchingCourses, containsInAnyOrder(repository.matching(criteria).toArray()));
}

@Test
void search_courses_using_a_criteria_without_hitting_the_inner_repository_the_second_time() {
BackofficeCourse matchingCourse = BackofficeCourseMother.create("DDD en Java", "3 days");
BackofficeCourse anotherMatchingCourse = BackofficeCourseMother.create("DDD en TypeScript", "2.5 days");
List<BackofficeCourse> matchingCourses = Arrays.asList(matchingCourse, anotherMatchingCourse);

Criteria criteria = BackofficeCourseCriteriaMother.nameAndDurationContains("DDD", "days");

shouldSearchMatching(criteria, matchingCourses);

assertThat(matchingCourses, containsInAnyOrder(repository.matching(criteria).toArray()));
assertThat(matchingCourses, containsInAnyOrder(repository.matching(criteria).toArray()));
}

private void shouldSearchAll(List<BackofficeCourse> courses) {
Mockito.when(innerRepository.searchAll()).thenReturn(courses);
}

private void shouldSearchMatching(Criteria criteria, List<BackofficeCourse> courses) {
Mockito.when(innerRepository.matching(criteria)).thenReturn(courses);
}

private void shouldHaveSaved(BackofficeCourse course) {
verify(innerRepository, atLeastOnce()).save(course);
}
}
10 changes: 10 additions & 0 deletions src/shared/main/tv/codely/shared/domain/criteria/Criteria.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,14 @@ public Optional<Integer> offset() {
public boolean hasFilters() {
return filters.filters().size() > 0;
}

public String serialize() {
return String.format(
"%s~~%s~~%s~~%s",
filters.serialize(),
order.serialize(),
offset.orElse(0),
limit.orElse(0)
);
}
}
4 changes: 4 additions & 0 deletions src/shared/main/tv/codely/shared/domain/criteria/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ public FilterOperator operator() {
public FilterValue value() {
return value;
}

public String serialize() {
return String.format("%s.%s.%s", field.value(), operator.value(), value.value());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,8 @@ public static FilterOperator fromValue(String value) {
public boolean isPositive() {
return this != NOT_EQUAL && this != NOT_CONTAINS;
}

public String value() {
return operator;
}
}
4 changes: 4 additions & 0 deletions src/shared/main/tv/codely/shared/domain/criteria/Filters.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public static Filters none() {
public List<Filter> filters() {
return filters;
}

public String serialize() {
return filters.stream().map(Filter::serialize).collect(Collectors.joining("^"));
}
}
4 changes: 4 additions & 0 deletions src/shared/main/tv/codely/shared/domain/criteria/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ public OrderType orderType() {
public boolean hasOrder() {
return !orderType.isNone();
}

public String serialize() {
return String.format("%s.%s", orderBy.value(), orderType.value());
}
}

0 comments on commit 9c6a54f

Please sign in to comment.