Объединение данных с нескольких репозиториев

Есть несколько репозиториев

ObjectRep - объекты

ObjTypeRep - описание типов объектов

TreeRep - дерево вложенностей

MotionRep - текущие параметры/состояние объекта (данных может и не быть)

На экране дерево объектов нужно показать join из всех этих репозиториев.

Как я думал это сделать:

1й вариант) Сделать

class ObjectsInteractor @Inject constructor(
    private val objectRepository: ObjectRepository,
    private val treeRepository: TreeRepository,
    private val objectTypesRepository: ObjTypesRepository,
    private val motionRepositry: MotionRepositry
){//.....}

и внутри этого интерактора все собирать. Но это не выгодно, т.к. ObjectRepository возвращает List объектов и на каждый объект нужно дополнительно запросить ObjTypeRep и MotionRep (условно в цикле).

2й вариант) Сделать SuperObjectRepository из которого будет приходить собранный ответ. Выгода в том, что SuperObjectRepository будет получать данные из Room (Select join join) и выборка всех данных за одну операцию.. Но и есть минус, то, что получается какой-то монстр(выгода которого сразу исчезает если не будет Room с его joinами..).

Как быть? Нужно грамотное решение)

Используется:

  • Rx
  • Kotlin
  • Room
  • Retrofit

UP. Сделал по первому варианту вот так. В интеракторе есть метод получения "Дерево". Единственное, я не на каждый объект по одному запрашиваю MotionRep, а запрашиваю списком и потом соединяю объекты с соответствующими motionState`ами.

Открыт к предложениям по оптимизации кода) p.s. по производительности в любом случае быстрее вариант №2.

fun getTreeObjects(parentFolderId: Long): Observable<TreeObject> {
        return treeRepository.getTree(parentId = parentFolderId)
            .flatMapObservable { tree ->
                objectRepository.getObjects(parentFolderId)
                    .observeOn(Schedulers.io())
                    .flatMapObservable { objList ->
                        objList.map { it.id }.let { ids ->
                            motionRepositry.getMotionStates(objectIds = ids)
                                .defaultIfEmpty(emptyList()) //если нет данных то мутируем в пустой список
                                .map { motionState ->
                                    objList.map { obj ->
                                        Pair(
                                            obj,
                                            motionState.findLast { it.objectId == obj.id }
                                        )
                                    }
                                }
                        }
                    }
                    .observeOn(Schedulers.io())
                    .map { objects -> TreeObject(tree, objects) }
            }
            .observeOn(AndroidSchedulers.mainThread())
    }

Ответы (1 шт):

Автор решения: Sergei Buvaka

Раз уж вы используете RX Java используйте ваш первый вариант. Но с одним нюансом. Создайте цепочку запросов с помощью метода combainLatest().

Observables.combineLatest(
                    objectRepository.getObjects(parentFolderId),
                    motionRepositry.getMotionStates(objectIds = ids),
                    ::combineData 
                )

CombineData это ваш собественный метод в котором вы будете комбинировать ваши данные. Вы можете использовать и более двух аргументов в combineLatest()

→ Ссылка