PolyBooks/sdp_polyBooks

View on GitHub
app/src/main/java/com/github/polybooks/database/CachedBookProvider.kt

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
package com.github.polybooks.database

import com.github.polybooks.core.Book
import com.github.polybooks.core.ISBN
import com.github.polybooks.utils.listOfFuture2FutureOfList
import com.github.polybooks.utils.order
import java.util.concurrent.CompletableFuture


/**
 * A cached BookProvider uses one BookProvider as cache for another one. Queries to the
 * CachedBookProvider are first going to look into the cache, and then in the backing book provider
 * for results.
 * */
class CachedBookProvider(private val backing: BookProvider, private val cache: BookProvider):
    BookProvider {

    override fun getBooks(
        isbns: Collection<ISBN>,
        ordering: BookOrdering
    ): CompletableFuture<List<Book>> {
        val booksFromCacheFuture = cache.getBooks(isbns)
        return booksFromCacheFuture.thenCompose { booksFromCache ->
            val isbnsFound = booksFromCache.map { it.isbn }
            val remainingISBNs = isbns.minus(isbnsFound)
            val booksFromBackingFuture = backing.getBooks(remainingISBNs)
            val allBooksFuture = booksFromBackingFuture.thenApply { booksFromBacking ->
                booksFromBacking + booksFromCache
            }
            val cachingBooksFuture = booksFromBackingFuture.thenCompose { booksFromBacking ->
                val futures = booksFromBacking.map { book -> cache.addBook(book) }
                return@thenCompose listOfFuture2FutureOfList(futures)
            }
            cachingBooksFuture.thenCompose { allBooksFuture }.thenApply { order(it, ordering) }
        }
    }

    override fun addBook(book: Book): CompletableFuture<Unit> {
        val cacheFuture = cache.addBook(book)
        val backingFuture = backing.addBook(book)
        return CompletableFuture.allOf(cacheFuture, backingFuture).thenApply { }
    }

}