Reputation: 26034
To build a complete User
entity, I need to perform this tasks:
UserResponse
(REST API response) from a userId
List<Role>
from a userId
Address
from the UserResponse.addressId
User
from the UserResponse
and the List<Role>
and the Address
.I tried this:
public Observable<User> getUserById(String userId) {
return Observable.zip(getUserResponse(userId), getRoles(userId), new Func2<UserResponse, List<Role>, User>() {
@Override
public User call(UserResponse response, List<Role> roles) {
//I need the address here!
}
});
But I don't know how to get the Address
from the UserResponse.addressId
using AddressRepository
.
public interface AddressRepository {
Observable<Address> getAddress(String addressId);
}
The User
constructor looks like:
public User(String userId, Address address, List<Role> roles) { ... }
I hope you understand. It's hard to explain the problem.
Upvotes: 1
Views: 68
Reputation: 3083
You can use a variant of flatMap
do something like
public Observable<User> getUserById(String userId) {
return Observable.zip(
getUserResponse(userId).flatMap(new Func1<UserResponse, Observable<Address>>() {
@Override
public Observable<Address> call(UserResponse resp) {
return addressRepository.getAddress(resp.addressId);
}
},
new Func2<UserResponse, Address, Pair<UserResponse,Address>>() {
@Override
public Pair<UserResponse,Address> call(UserResponse resp, Address addr) {
return new Pair<UserResponse,Address>(resp,addressRepository.getAddress(resp.addressId));
}
}),
getRoles(userId),
new Func2<Pair<UserResponse, Address>, List<Role>, User>(){
@Override
public User call(UserResponse resp, Address ad, List<Role> roles) {
//Now, I have all I need to build the User
}
}
);
}
Upvotes: 1
Reputation: 16142
Use the cache()
operator:
public Observable<User> getUserById(String userId) {
Observable<UserResponse> response = getUserResponse(userId).cache();
return Observable.zip(
response,
response.flatMap(new Func1<UserResponse, Observable<Address>>() {
@Override
public Observable<Address> call(UserResponse resp) {
return addressRepository.getAddress(resp.addressId);
}
}),
getRoles(userId), new Func3<UserResponse, Address, List<Role>, User>() {
@Override
public User call(UserResponse resp, Address ad, List<Role> roles) {
//Now, I have all I need to build the User =)
}
}
});
}
Upvotes: 2
Reputation: 1554
getUserResponse(userId).publish.autoConnect(2);
Will make it a ConnectableObservable and only start publishing where are there 2 subscribers and in this way you will be calling the backend only once.
getUserAddress() will call the getUserResponse and get the address out of it.
Now zip getUserResponse, getUserAddress and getRoles(userId) all together :)
Upvotes: 1
Reputation: 26034
I found a solution:
public Observable<User> getUserById(String userId) {
return Observable.zip(
getUserResponse(userId),
getUserResponse(userId).flatMap(new Func1<UserResponse, Observable<Address>>() {
@Override
public Observable<Address> call(UserResponse resp) {
return addressRepository.getAddress(resp.addressId);
}
}),
getRoles(userId), new Func3<UserResponse, Address, List<Role>, User>() {
@Override
public User call(UserResponse resp, Address ad, List<Role> roles) {
//Now, I have all I need to build the User =)
}
}
});
Any comment will be appreciated. Is it a good practice to "repeat" the call to getUserResponse(userId)
? I didn't find another way to solve this.
Upvotes: 0