Commit e8b55308 authored by Vladislav's avatar Vladislav

fetch estates with update

parent e6aa7f16
...@@ -175,6 +175,10 @@ dependencies { ...@@ -175,6 +175,10 @@ dependencies {
//RxKotlin //RxKotlin
implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion") implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion")
//Arch Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
//Tests //Tests
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0'
......
...@@ -16,6 +16,7 @@ import com.biganto.visual.roompark.domain.model.EstateModel ...@@ -16,6 +16,7 @@ import com.biganto.visual.roompark.domain.model.EstateModel
import com.biganto.visual.roompark.domain.model.fromEntity import com.biganto.visual.roompark.domain.model.fromEntity
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.rxkotlin.Observables
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
...@@ -37,17 +38,31 @@ class EstateRepository @Inject constructor( ...@@ -37,17 +38,31 @@ class EstateRepository @Inject constructor(
Timber.d("Estate Repository Created $this") Timber.d("Estate Repository Created $this")
} }
override fun fetchFavorites(user:UserEntity): Observable<Iterable<EstateEntity>> = override fun fetchFavorites(user:UserEntity): Observable<List<EstateEntity>> =
Observables.zip(
api.getFavorites(user.authToken) api.getFavorites(user.authToken)
.doOnError(Timber::e) .doOnError(Timber::e)
.map { fromRawList(it, ::fromRaw) } .map { fromRawList(it, ::fromRaw) }
.doOnNext { ,db.getUserFavorites(user.uuid)
it.forEach { estate -> .defaultIfEmpty(null).toList().toObservable()
estate.setFavorite(true) .doOnError(Timber::e)
estate.user = user ){apiList,dbList ->
} if (dbList.isEmpty())
return@zip apiList
dbList
.filterNotNull()
.filter {dbFav -> apiList.map{it.id}.contains(dbFav.id) }
.let{ db.deleteEstate(it) }
apiList.forEach { estate ->
estate.setFavorite(true)
estate.user = user
} }
return@zip apiList
}
.flatMap(db::upsertEstates) .flatMap(db::upsertEstates)
.map { it.toList() }
.doOnNext{ db.refreshUser(user) } .doOnNext{ db.refreshUser(user) }
override fun fetchDeals(user:UserEntity): Observable<List<EstateEntity>> = override fun fetchDeals(user:UserEntity): Observable<List<EstateEntity>> =
...@@ -80,7 +95,7 @@ class EstateRepository @Inject constructor( ...@@ -80,7 +95,7 @@ class EstateRepository @Inject constructor(
.doOnNext{ db.refreshUser(user) } .doOnNext{ db.refreshUser(user) }
} }
private val getFavoritesDb: Observable<List<EstateEntity>> = private val getFavoritesDb: Observable<MutableList<EstateEntity?>>? =
local.recentUser() local.recentUser()
.flatMap { .flatMap {
when (it) { when (it) {
...@@ -95,12 +110,14 @@ class EstateRepository @Inject constructor( ...@@ -95,12 +110,14 @@ class EstateRepository @Inject constructor(
} }
override fun getFavorites(): Observable<List<EstateModel>> { override fun getFavorites(user:UserEntity): Observable<List<EstateModel>> {
return Observable.mergeDelayError( return Observable.mergeDelayError(
arrayListOf( arrayListOf(
getFavoritesApi, getFavoritesDb fetchFavorites(user), getFavoritesDb
) )
).map { fromEntity(it, ::fromEntity) } )
.map { it.filterNotNull() }
.map { fromEntity(it, ::fromEntity) }
.doOnError(Timber::e) .doOnError(Timber::e)
} }
......
package com.biganto.visual.roompark.data.memcache
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import com.jakewharton.rxrelay2.Relay
import com.jakewharton.rxrelay2.ReplayRelay
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
/**
* Created by Vladislav Bogdashkin on 19.10.2018.
*/
/**
* @param[maxSize] max entries count before automatic save && flush
* @param[flushInterval] time without any actions with cache in SECONDS before automatic save && flush
* */
abstract class EntityCache<K,V>
constructor(
private val maxSize: Int = 300,
private val flushInterval: Long = TimeUnit.MINUTES.toSeconds(1)
) : Cache<K,V> {
private val disposable = CompositeDisposable()
protected abstract fun saveDelegate (values:List<V>)
protected abstract fun readDelegate (key:K) : V?
protected abstract fun deleteDelegate (value:V)
protected val notifier: Relay<V> = ReplayRelay.create<V>().toSerialized()
init {
disposable.addAll(
Observable.interval(flushInterval, flushInterval, TimeUnit.SECONDS)
.doOnTerminate { clear() }
.doOnDispose { clear() }
.subscribe { clear() }
)
}
override fun contains(key: K): Boolean = keyMap.containsKey(key)
protected val locker = Any()
private var lastFlushTime = System.nanoTime()
private val keyMap = ConcurrentHashMap<K, V>()
override val size: Int
get() = keyMap.size
override val toList
get() = keyMap.toList()
fun deleteEntity(key: K){
synchronized(locker) {
deleteItem(key)
}
}
private fun deleteItem(key:K){
synchronized(locker) {
lastFlushTime = System.nanoTime()
var toDelete = keyMap.remove(key)
if (toDelete == null)
toDelete = readDelegate(key)
if (toDelete == null) return // -> нет в хранилище
deleteDelegate(value = toDelete)
}
}
fun deleteEntitys(keys: List<K>){
synchronized(locker) {
keys.forEach { deleteItem(it)}
}
}
override fun set(key: K, value: V?) {
synchronized(locker) {
lastFlushTime = System.nanoTime()
if (keyMap.size > maxSize)
clear()
value?.let {
keyMap[key]=it
notifier.accept(it)
}
}
}
override fun remove(key: K) = keyMap.remove(key)
override fun get(key: K): V? {
synchronized(locker) {
lastFlushTime = System.nanoTime()
return keyMap[key] ?: readDelegate(key)
}
}
override fun saveAll(){
synchronized(locker)
{
if (keyMap.size > 0) {
Timber.d("Going to save items: ${keyMap.values.size}")
saveDelegate(keyMap.values.toList())
}
}
}
override fun clear() {
if (keyMap.size == 0) return
synchronized(locker)
{
saveAll()
keyMap.clear()
}
}
override fun removeAll(): List<V>? {
val values= keyMap.values.toList()
keyMap.clear()
return values
}
private fun recycle() {
if (keyMap.size<=0) return
val shouldRecycle = System.nanoTime() - lastFlushTime >= TimeUnit.MILLISECONDS.toNanos(flushInterval)
if (!shouldRecycle) return
keyMap.clear()
}
}
interface Cache<K,V> {
val size: Int
val toList:List<Pair<K,V>>
operator fun set(key: K, value: V?)
fun contains(key: K): Boolean
operator fun get(key: K): V?
fun remove(key: K): V?
fun removeAll(): List<V>?
fun clear()
fun saveAll()
}
/**
* Suppress warning Leaking This as we sure to make singletone instance of object in single-thread
* more info and
* @see <a href="https://stackoverflow.com/questions/3921616/leaking-this-in-constructor-warning">discussion</a>
*/
@Suppress("LeakingThis")
abstract class LifeCycleCache<K,V>(size:Int, secondsToFlush:Long)
: EntityCache<K, V>(maxSize=size,flushInterval = secondsToFlush)
, LifecycleObserver
{
init {
ProcessLifecycleOwner.get().lifecycle
.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onAppPaused() {
saveAll()
}
}
...@@ -32,7 +32,7 @@ interface IDb { ...@@ -32,7 +32,7 @@ interface IDb {
fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity> fun getPhotos(albumId: Int): Observable<GalleryPhotoEntity>
fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity> fun getPhoto(photoId: Int): Observable<GalleryPhotoEntity>
fun getAlbum(albumId: Int): Observable<ImageAlbumEntity> fun getAlbum(albumId: Int): Observable<ImageAlbumEntity>
fun getUserFavorites(uuid: Int): Observable<EstateEntity> fun getUserFavorites(uuid: Int): Observable<EstateEntity?>
fun fetchAllUsers(): Observable<List<UserEntity>> fun fetchAllUsers(): Observable<List<UserEntity>>
fun getEstate(estateId: Int): Observable<EstateEntity> fun getEstate(estateId: Int): Observable<EstateEntity>
fun upsertEstate(entity: EstateEntity) fun upsertEstate(entity: EstateEntity)
...@@ -78,4 +78,6 @@ interface IDb { ...@@ -78,4 +78,6 @@ interface IDb {
fun upsertEstates(entity: List<EstateEntity>): Observable<Iterable<EstateEntity>>? fun upsertEstates(entity: List<EstateEntity>): Observable<Iterable<EstateEntity>>?
fun upsertDeals(entity: List<DealEntity>): Observable<Iterable<DealEntity>> fun upsertDeals(entity: List<DealEntity>): Observable<Iterable<DealEntity>>
fun deleteSubscriptions(entities: List<Subscription>) fun deleteSubscriptions(entities: List<Subscription>)
fun deleteEstate(entity: List<EstateEntity>)
fun deleteEstate(entity: EstateEntity)
} }
\ No newline at end of file
...@@ -190,7 +190,7 @@ class RequeryRepository @Inject constructor( ...@@ -190,7 +190,7 @@ class RequeryRepository @Inject constructor(
.get() .get()
.observableResult() .observableResult()
override fun getUserFavorites(uuid: Int): Observable<EstateEntity> = override fun getUserFavorites(uuid: Int): Observable<EstateEntity?> =
store.select(EstateEntity::class) store.select(EstateEntity::class)
.where(EstateEntity.USER_ID.eq(uuid)) .where(EstateEntity.USER_ID.eq(uuid))
.and(EstateEntity.FAVORITE.eq(true)) .and(EstateEntity.FAVORITE.eq(true))
...@@ -409,6 +409,10 @@ class RequeryRepository @Inject constructor( ...@@ -409,6 +409,10 @@ class RequeryRepository @Inject constructor(
.where(TourFileJunctionEntity.TOUR.eq(tourId)) .where(TourFileJunctionEntity.TOUR.eq(tourId))
.get() .get()
override fun deleteEstate(entity:EstateEntity) = deleteBlocking(entity)
override fun deleteEstate(entity:List<EstateEntity>) = deleteBlocking(entity)
override fun deleteFile(entity:FileEntity) = deleteBlocking(entity) override fun deleteFile(entity:FileEntity) = deleteBlocking(entity)
override fun deleteFiles(entity:List<FileEntity>) = deleteBlocking(entity) override fun deleteFiles(entity:List<FileEntity>) = deleteBlocking(entity)
......
package com.biganto.visual.roompark.domain.contract package com.biganto.visual.roompark.domain.contract
import com.biganto.visual.roompark.data.repository.db.requrey.model.DealEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.EstateEntity
import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity import com.biganto.visual.roompark.data.repository.db.requrey.model.UserEntity
import com.biganto.visual.roompark.domain.model.DealModel import com.biganto.visual.roompark.domain.model.DealModel
...@@ -15,11 +14,12 @@ import io.reactivex.Observable ...@@ -15,11 +14,12 @@ import io.reactivex.Observable
interface DealContract{ interface DealContract{
fun getFavorites() : Observable<List<EstateModel>> // fun getFavorites() : Observable<List<EstateModel>>
fun getEstate(estateId: Int): Observable<EstateModel> fun getEstate(estateId: Int): Observable<EstateModel>
fun getDeals(): Observable<List<DealModel>> fun getDeals(): Observable<List<DealModel>>
fun fetchEstate(building: Int, number: Int): Observable<EstateModel> fun fetchEstate(building: Int, number: Int): Observable<EstateModel>
fun setDealRead(dealId: String): Completable fun setDealRead(dealId: String): Completable
fun fetchDeals(user: UserEntity): Observable<List<EstateEntity>> fun fetchDeals(user: UserEntity): Observable<List<EstateEntity>>
fun fetchFavorites(user: UserEntity): Observable<Iterable<EstateEntity>> fun fetchFavorites(user: UserEntity): Observable<List<EstateEntity>>
fun getFavorites(user: UserEntity): Observable<List<EstateModel>>
} }
\ No newline at end of file
package com.biganto.visual.roompark.domain.use_case package com.biganto.visual.roompark.domain.use_case
import com.biganto.visual.roompark.domain.contract.AuthContract
import com.biganto.visual.roompark.domain.contract.DealContract import com.biganto.visual.roompark.domain.contract.DealContract
import com.biganto.visual.roompark.domain.contract.FlatPlanContract import com.biganto.visual.roompark.domain.contract.FlatPlanContract
import com.biganto.visual.roompark.domain.model.EstateModel
import io.reactivex.Observable
import javax.inject.Inject import javax.inject.Inject
/** /**
...@@ -10,10 +13,13 @@ import javax.inject.Inject ...@@ -10,10 +13,13 @@ import javax.inject.Inject
class EstateUseCase @Inject constructor( class EstateUseCase @Inject constructor(
private val contract: DealContract, private val contract: DealContract,
private val planContract: FlatPlanContract private val planContract: FlatPlanContract,
private val authContract: AuthContract
) { ) {
fun fetchFavorites() = contract.getFavorites() fun fetchFavorites(): Observable<List<EstateModel>> =
authContract.currentUser()
.flatMap (contract::getFavorites)
fun getEstate(estateId: Int) = contract.getEstate(estateId) fun getEstate(estateId: Int) = contract.getEstate(estateId)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment