Héctor
Héctor

Reputation: 26034

Unable to build this Observable

To build a complete User entity, I need to perform this tasks:

  1. Get a UserResponse (REST API response) from a userId
  2. Get a List<Role> from a userId
  3. Get a Address from the UserResponse.addressId
  4. Build the 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

Answers (4)

JohnWowUs
JohnWowUs

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

Tassos Bassoukos
Tassos Bassoukos

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

Zahid Rasheed
Zahid Rasheed

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

H&#233;ctor
H&#233;ctor

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

Related Questions