package org.mercury_im.messenger.data.repository; import org.mercury_im.messenger.data.mapping.AccountMapping; import org.mercury_im.messenger.data.model.AccountModel; import org.mercury_im.messenger.data.repository.dao.AccountDao; import org.mercury_im.messenger.util.Optional; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.util.ThreadUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import javax.inject.Inject; import javax.inject.Named; import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.Scheduler; import io.reactivex.Single; import io.requery.Persistable; import io.requery.query.ResultDelegate; import io.requery.reactivex.ReactiveEntityStore; import io.requery.reactivex.ReactiveResult; public class XmppAccountRepository extends RequeryRepository implements AccountRepository { private final AccountMapping accountMapping; private final AccountDao dao; @Inject public XmppAccountRepository(ReactiveEntityStore data, @Named(value = ThreadUtils.SCHEDULER_IO) Scheduler subscriberScheduler, @Named(value = ThreadUtils.SCHEDULER_UI) Scheduler observerScheduler, AccountMapping accountMapping) { super(data, subscriberScheduler, observerScheduler); this.accountMapping = accountMapping; this.dao = new AccountDao(data); } @Override public Single insertAccount(Account account) { return Single.just(account) .map(accountMapping::toModel) .flatMap(dao::insert) .map(model -> accountMapping.toEntity(model, account)) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Observable> observeAccount(UUID accountId) { return dao.get(accountId).observableResult() .map(result -> new Optional<>(result.firstOrNull())) .map(accountMapping::toEntity) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Maybe getAccount(UUID accountId) { return dao.get(accountId).maybe() .map(accountMapping::toEntity) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Observable> observeAccountByAddress(String address) { return dao.get(address).observableResult() .map(result -> new Optional<>(result.firstOrNull())) .map(accountMapping::toEntity) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Maybe getAccountByAddress(String address) { return dao.get(address).maybe() .map(accountMapping::toEntity) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Observable> observeAllAccounts() { return dao.getAll().observableResult() .map(ResultDelegate::toList) .map(this::modelsToEntities) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Observable observeAccounts() { return dao.getAll().observableResult() .flatMap(ReactiveResult::observable) .map(accountMapping::toEntity) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Single updateAccount(Account account) { // Since we cannot access setId() of AccountModel, we have to query the model by ID and update it manually. // https://github.com/requery/requery/issues/616#issuecomment-315685460 return dao.get(account.getId()).maybe().toSingle() .map(model -> accountMapping.toModel(account, model)) .flatMap(updatedModel -> data().update(updatedModel)) .map(model -> accountMapping.toEntity(model, account)) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Single upsertAccount(Account account) { return dao.get(account.getId()).maybe() .switchIfEmpty( Single.just(account).map(accountMapping::toModel).flatMap(dao::insert)) .map(model -> accountMapping.toModel(account, model)) .flatMap(data()::update) .map(model -> accountMapping.toEntity(model, account)) .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } @Override public Completable deleteAccount(UUID accountId) { return dao.delete(accountId).ignoreElement() .subscribeOn(subscriberScheduler()) .observeOn(observerScheduler()); } private List modelsToEntities(List models) { List entities = new ArrayList<>(models.size()); for (AccountModel model : models) { entities.add(accountMapping.toEntity(model)); } return entities; } }