Coverage Summary for Class: SearchHistoryRepository (concept.stc.data)
Class |
Method, %
|
Branch, %
|
Line, %
|
SearchHistoryRepository |
100%
(8/8)
|
50%
(1/2)
|
100%
(22/22)
|
SearchHistoryRepository$getAllSearches$suspendImpl$$inlined$map$1 |
SearchHistoryRepository$getAllSearches$suspendImpl$$inlined$map$1$2 |
SearchHistoryRepository$getAllSearches$suspendImpl$$inlined$map$1$2$1 |
SearchHistoryRepository$getMovieIdsBySearch$1 |
SearchHistoryRepository$getMovieIdsBySearch$suspendImpl$$inlined$map$1 |
SearchHistoryRepository$getMovieIdsBySearch$suspendImpl$$inlined$map$1$2 |
SearchHistoryRepository$getMovieIdsBySearch$suspendImpl$$inlined$map$1$2$1 |
SearchHistoryRepository$getSearchByQuery$1 |
SearchHistoryRepository$saveMovieIdsForSearch$1 |
SearchHistoryRepository$saveSearch$1 |
SearchHistoryRepository$saveSearch$2 |
SearchHistoryRepository$updateMovieIdsForSearch$1 |
Total |
100%
(8/8)
|
50%
(1/2)
|
100%
(22/22)
|
package concept.stc.data
import concept.stc.data.local.SearchHistoryCrudRepository
import concept.stc.data.local.SearchMoviesCrudRepository
import concept.stc.data.local.entity.SearchEntity
import concept.stc.data.local.entity.SearchToMovieReference
import concept.stc.data.mapper.toDomain
import concept.stc.data.mapper.toEntity
import concept.stc.domain.model.Movie
import concept.stc.domain.model.Search
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.count
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.time.LocalDateTime
/**
* The repository to manage local data of search history.
* Repository can aggregate data from multiple CRUD repositories (tables)
* and convert it to domain models. Repository behaves as a data facade
* that hides the database internal structure from domain services.
*
* @param searchDao the CRUD repository to get search history from a local database.
* @param referencesDao the CRUD repository to get references from search to movies.
*/
@Component
class SearchHistoryRepository(
private val searchDao: SearchHistoryCrudRepository,
private val referencesDao: SearchMoviesCrudRepository
) {
private val logger = LoggerFactory.getLogger(this::class.java)
/**
* Get all recent searches from history.
*
* @return the flow that emits domain [Search] models.
*/
suspend fun getAllSearches(): Flow<Search> = searchDao
.findAll().map { it.toDomain() }
/**
* Get search from history.
*
* @return the domain [Search] model or null if not found.
*/
suspend fun getSearchByQuery(query: String): Search? = searchDao
.getSearchHistoryByQuery(query)?.toDomain()
/**
* Save a new search into a local database.
* The search query is saved with the current date.
*
* @param query the search query.
*
* @return the domain [Search] model.
*/
suspend fun saveSearch(query: String): Search {
val entity = SearchEntity(query = query, updatedDate = LocalDateTime.now())
return searchDao.save(entity).toDomain()
}
/**
* Save a new search or update an existing search in the local database.
*
* @param search the search domain model.
*
* @return the domain [Search] model.
*/
suspend fun saveSearch(search: Search): Search = searchDao
.save(search.toEntity()).toDomain()
/**
* Get all movie ids associated with a specific search id.
*
* @param search the search domain model.
*
* @return the flow that emits domain [Movie] models.
*/
suspend fun getMovieIdsBySearch(search: Search): Flow<Int> = referencesDao
.getReferencesBySearchId(search.id)
.map { reference -> reference.movieId }
/**
* Associate movie ids with a specific search id.
*
* @param search the search domain model.
*/
suspend fun saveMovieIdsForSearch(search: Search, movieIds: List<Int>) {
val references = movieIds.map { SearchToMovieReference(searchId = search.id, movieId = it) }
val entities = referencesDao.saveAll(references)
logger.info("Saved ${entities.count()} references for search ${search.query}")
}
/**
* Update movie ids associated with a specific search ID.
*
* @param search the search domain model.
*/
suspend fun updateMovieIdsForSearch(search: Search, movieIds: List<Int>) {
val references = referencesDao.getReferencesBySearchId(search.id).toList()
val existingMovieIds = references.map { it.movieId }
val newMoviesIds = movieIds.filter { movieId -> !existingMovieIds.contains(movieId) }
saveMovieIdsForSearch(search, newMoviesIds)
}
}