Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava and Sqlbrite - what operator to use

I started using RxJava in combination with SqlBrite and I am having some issues with the zip operator.

Let's say I have 2 classes, User and Tweet.

public class User {
    public long id;
    public List<Tweet> users;
    ...
}

public class Tweet {
    public long id;
    public User poster;
    ...
}

And their respective SQLite tables:

user
---------
id INTEGER PRIMARY KEY

tweet
---------
id INTEGER PRIMARY KEY
poster_id INTEGER
FOREIGN KEY(poster_id) REFERENCES user(id)

and their respective SqlBrite DAO

UserDao:

public class UserDao {
    private final BriteDatabase briteDb;
    private final TweetDAO tweetDao;

    ...

    public Observable<List<User>> getUsersWithTheirTweets() {
        Observable<User> usersObs = briteDb.createQuery("user", "SELECT * FROM user")
                .map(new Func1<SqlBrite.Query, List<User>>() {
                    @Override
                    public List<User> call(SqlBrite.Query query) {
                        Cursor cursor = query.run();
                        List<User> result = new ArrayList<>(cursor.getCount());
                        while (cursor.moveToNext()) {
                            User user = UserTable.parseCursor(cursor);
                            result.add(user);
                        }
                        cursor.close();
                        return result;
                    }
                })
                // transform Observable<List<User>> into Observable<User>
                .flatMap(new Func1<List<User>, Observable<User>>() {
                    @Override
                    public Observable<User> call(List<User> users) {
                        return Observable.from(users);
                    }
                });

        // combine each user with his tweets
        return Observable.zip(usersObs, usersObs.flatMap(new Func1<User, Observable<List<Tweet>>>() {
            @Override
            public Observable<List<Tweet>> call(User user) {
                return tweetDao.getTweetsByUser(user);
            }
        }), new Func2<User, List<Tweet>, User>() {
            @Override
            public User call(User user, List<Tweet> tweets) {
                user.tweets = tweets;
                return user;
            }
        }).toList();
    }

}

TweetDAO:

public class TweetDAO {
    private final BriteDatabase briteDb;

    ...

    public Observable<List<Tweet>> getTweetsForUser(final User user) {
        briteDb.createQuery("tweet", "SELECT * FROM tweet WHERE poster_id = ?", Long.toString(user.id))
                .map(new Func1<SqlBrite.Query, List<User>>() {
                    @Override
                    public List<Tweet> call(SqlBrite.Query query) {
                        Cursor cursor = query.run();
                        List<Tweet> result = new ArrayList<>(cursor.getCount());
                        while (cursor.moveToNext()) {
                            Tweet tweet = TweetTable.parseCursor(cursor);
                            tweet.user = user;
                            result.add(tweet);
                        }
                        cursor.close();
                        return result;
                    }
                })
    }
}

As you can see in UserDao, I tried to use the a combination of zip and flatMap operators to populate the list of Tweet for each User.

First question: is there a better way to do that?

Second question: that zip operator seems to hang forever and never completes... I see that tweetDao.getTweetsByUser(user) is called but the Func of the zip is never called... Would anyone have an idea why?

Third question: is there a better way of transforming an Observable<List<T>> to an Observable<T> other than using a combination of flatMap and from ?

Damn, that RxJava is powerful but the learning curve is pretty steep...

like image 640
Simon Reggiani Avatar asked Aug 31 '15 18:08

Simon Reggiani


1 Answers

Why not let the database handle the join?

SELECT * FROM user INNER JOIN tweet ON user._id = tweet.poster_id

You might have to rename some columns if the two tables have columns with the same name.

More about joins here

like image 141
LordRaydenMK Avatar answered Oct 19 '22 22:10

LordRaydenMK