package org.mercury_im.messenger.data.repository; import org.mercury_im.messenger.core.data.repository.AccountRepository; import org.mercury_im.messenger.core.data.repository.PeerRepository; import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.data.mapping.PeerMapping; import org.mercury_im.messenger.data.model.PeerModel; import org.mercury_im.messenger.entity.Account; import org.mercury_im.messenger.entity.contact.Peer; import java.util.ArrayList; import java.util.List; import java.util.UUID; import javax.inject.Inject; import io.reactivex.Completable; import io.reactivex.Maybe; import io.reactivex.Observable; import io.reactivex.Single; import io.requery.Persistable; import io.requery.query.ResultDelegate; import io.requery.reactivex.ReactiveEntityStore; public class RxPeerRepository extends RequeryRepository implements PeerRepository { private final AccountRepository accountRepository; private final PeerMapping peerMapping; @Inject public RxPeerRepository(ReactiveEntityStore data, PeerMapping peerMapping, AccountRepository accountRepository) { super(data); this.peerMapping = peerMapping; this.accountRepository = accountRepository; } @Override public Single insertPeer(Peer peer) { return data().insert(peerMapping.toModel(peer, new PeerModel())) .map(model -> peerMapping.toEntity(model, peer)); } @Override public Observable> observePeer(UUID peerId) { return data().select(PeerModel.class) .where(PeerModel.ID.eq(peerId)) .get().observableResult() .map(result -> new Optional<>(peerMapping.toEntity(result.firstOrNull(), new Peer()))); } @Override public Maybe getPeer(UUID peerId) { return data().select(PeerModel.class) .where(PeerModel.ID.eq(peerId)) .get().maybe() .map(model -> peerMapping.toEntity(model, new Peer())); } @Override public Observable> observePeerByAddress(UUID accountId, String address) { return data().select(PeerModel.class) .where(PeerModel.ACCOUNT_ID.eq(accountId)) .and(PeerModel.ADDRESS.eq(address)) .get().observableResult() .map(result -> new Optional<>(result.firstOrNull())) .map(peerMapping::toEntity); } @Override public Single getOrCreatePeer(UUID accountId, String address) { return accountRepository.getAccount(accountId).toSingle() .flatMap(account -> getOrCreatePeer(account, address)); } @Override public Maybe getPeerByAddress(UUID accountId, String address) { return data().select(PeerModel.class) .where(PeerModel.ACCOUNT_ID.eq(accountId)) .and(PeerModel.ADDRESS.eq(address)) .get().maybe() .map(peerMapping::toEntity); } @Override public Single getOrCreatePeer(Account account, String address) { return getPeerByAddress(account, address) .switchIfEmpty( Single.just(new Peer()) .map(peer -> { peer.setAccount(account); peer.setAddress(address); return peer; }) .flatMap(this::upsertPeer)); } @Override public Observable> observeAllPeers() { return data().select(PeerModel.class) .orderBy(PeerModel.ADDRESS) .get().observableResult() .map(ResultDelegate::toList) .map(this::peerModelsToEntities); } private List peerModelsToEntities(List peerModels) { List peerEntities = new ArrayList<>(peerModels.size()); for (PeerModel model : peerModels) { peerEntities.add(peerMapping.toEntity(model)); } return peerEntities; } @Override public Observable> observeAllContactsOfAccount(UUID accountId) { return data().select(PeerModel.class) .where(PeerModel.ACCOUNT_ID.eq(accountId)) //.and(isContact()) .get().observableResult() .map(ResultDelegate::toList) .map(this::peerModelsToEntities); } @Override public Single updatePeer(Peer peer) { // In order to update, we fetch the model, update it and write it back. return data().select(PeerModel.class) .where(PeerModel.ID.eq(peer.getId())) .get().maybe().toSingle() // write changes into model .map(model -> peerMapping.toModel(peer, model)) .flatMap(data()::update) .map(model -> peerMapping.toEntity(model, peer)); } @Override public Single upsertPeer(Peer peer) { return data().select(PeerModel.class) .where(PeerModel.ID.eq(peer.getId())) .get().maybe() // if not exists, create .switchIfEmpty(Single.just(peer) .map(peerMapping::toModel) .flatMap(data()::insert)) // write changes into fetched model .map(model -> peerMapping.toModel(peer, model)) // write changed model back to db .flatMap(data()::update) .map(model -> peerMapping.toEntity(model, peer)); } @Override public Completable deletePeer(Peer peer) { return data().delete(PeerModel.class) .where(PeerModel.ID.eq(peer.getId())) .get().single().ignoreElement(); } @Override public Completable deletePeer(UUID accountId, String address) { return data().delete(PeerModel.class) .where(PeerModel.ACCOUNT_ID.eq(accountId) .and(PeerModel.ADDRESS.eq(address))) .get().single().ignoreElement(); } @Override public Completable deleteAllPeers(UUID accountId) { return data().delete(PeerModel.class) .where(PeerModel.ACCOUNT_ID.eq(accountId)) .get().single().ignoreElement(); } }