Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relations example #436

Closed
TheRishka opened this issue Jul 14, 2015 · 16 comments
Closed

Relations example #436

TheRishka opened this issue Jul 14, 2015 · 16 comments
Assignees
Labels

Comments

@TheRishka
Copy link

Could you please add some more complex sample-app with an example of making many-to-many relations? I've implemented storIO in my project quite successfully but now i'm stuck at creating more complex databases. I understand that it refers more to SQLite, but your vision on resolving this would be much helpful. Thank you!

@artem-zinnatullin
Copy link
Member

Sure, you are second person who asks this, I'd work on it today/tomorrow.

@Rainer-Lang
Copy link

Please also add me.

@fdorssers
Copy link

I'm also looking forward to seeing how you would implement this using StorIO. For example adding an author class to your current sample and having multiple tweets refer to the same author.

@artem-zinnatullin
Copy link
Member

I'd make it like this:

// Pseudo code

class User {
  String email;
}

class Tweet {
  User user;
  String content;
}

class TweetGetResolver extends GetResolver  {
  @Override @NonNull public Tweet mapFromCursor(@NonNull Cursor cursor) {
    String userName = cursor.getString(cursor.getColumnIndex("user"));
    String content = cursor.getString(cursor.getColumnIndex("content"));
    User user = …; // get user by name
    return Tweet.newInstance(user, content);
  }
}

@Rainer-Lang
Copy link

Please also lists.
I'm thinking about using StorIO instead of an orm-lib.

@dimsuz
Copy link

dimsuz commented Aug 19, 2015

@artem-zinnatullin in your example above, what should I put instead of "//get user by name"? For example if User is stored in another table. can I use storIO instance to perform another blocking call here? Is it good to do this inside a Resolver? Or is this the wrong approach and "raw query" + "join" should be used instead?

@artem-zinnatullin
Copy link
Member

cc all interested in this issue: take a look at #494, it's my vision of relations with StorIO.

Feel free to ask any questions here.

@dimsuz

In your example above, what should I put instead of "//get user by name"? For example if User is stored in another table. can I use storIO instance to perform another blocking call here?

Yes, feel free to use StorIO methods to do what you need to do (get other objects and so on, see PR #494), of course you can use raw queries too.

The only thing is that StorIO operations will create useless notification… I think we will eliminate them somehow later, it's not very critical.

@dimsuz
Copy link

dimsuz commented Aug 20, 2015

@artem-zinnatullin sadly, I cannot reuse storIO object in mapFromCursor and this means that all my relation-based 'get' queries must be rewritten to raw queries with JOIN which kinda defeats the whole purpose of fluent API which Query brings us - and now I need to have all those DAO-like classes again which would hide all those raw queries behind nicer interfaces like Relations.java in your example. Imagine I also need that JOIN but with some additional 'where' - that's one more method in that class, then more and more will come :)

@artem-zinnatullin
Copy link
Member

@dimsuz why you can not reuse StorIO methods in mapFromCursor()? You can make custom query but reuse type-mapping :)

@dimsuz
Copy link

dimsuz commented Aug 20, 2015

mapFromCursor() doesn't have storIO argument passed in. It gets passed only to other methods of Resolver class (e.g. performGet). So I could reuse it in resolver's mapFromCursor() only by overriding performGet and saving it as field. But judging from API it is not clear whether it is safe to do so or not. It is passed by argument to limited set of methods contrary to having some getStoreIO() method => so by looking at API alone I would assume I shouldn't store it :)

@artem-zinnatullin
Copy link
Member

I'll add more javadoc for operation resolvers. Feel free to use most abstract operation resolvers, we've added default implementations to save users from boilerplate :)

@dimsuz
Copy link

dimsuz commented Aug 20, 2015

So you are saying that the way to do this would be to store reference in resolver field and use it in mapFromCursor?

@artem-zinnatullin
Copy link
Member

So you are saying that the way to do this would be to store reference in resolver field and use it in mapFromCursor?

Nope, it's not a good solution, because potentially you can use same resolver for different StorIO instances, so I would not depend on this.

You can extend GetResolver, or just pass instances of GetResolvers of required classes.

Like this:

public class TweetWithUserGetResolver extends DefaultGetResolver<TweetWithUser> {

    @NonNull
    private final TweetGetResolver tweetGetResolver;

    @NonNull
    private final UserGetResolver userGetResolver;

    public TweetWithUserGetResolver(@NonNull TweetGetResolver tweetGetResolver, @NonNull UserGetResolver userGetResolver) {
        this.tweetGetResolver = tweetGetResolver;
        this.userGetResolver = userGetResolver;
    }

    // We expect that cursor will contain both Tweet and User: SQL JOIN
    @NonNull
    @Override
    public TweetWithUser mapFromCursor(@NonNull Cursor cursor) {
        final Tweet tweet = tweetGetResolver.mapFromCursor(cursor);
        final User user = userGetResolver.mapFromCursor(cursor);

        return new TweetWithUser(tweet, user);
    }
}

Instead of this:

public class TweetWithUserGetResolver extends DefaultGetResolver<TweetWithUser> {

    // We expect that cursor will contain both Tweet and User: SQL JOIN
    @NonNull
    @Override
    public TweetWithUser mapFromCursor(@NonNull Cursor cursor) {
        final Tweet tweet = Tweet.newTweet(
                cursor.getLong(cursor.getColumnIndexOrThrow(TweetsTable.COLUMN_ID)),
                cursor.getString(cursor.getColumnIndexOrThrow(TweetsTable.COLUMN_AUTHOR)),
                cursor.getString(cursor.getColumnIndexOrThrow(TweetsTable.COLUMN_CONTENT))
        );

        final User user = User.newUser(
                cursor.getLong(cursor.getColumnIndexOrThrow(UsersTable.COLUMN_ID)),
                cursor.getString(cursor.getColumnIndexOrThrow(UsersTable.COLUMN_NICK))
        );

        return new TweetWithUser(tweet, user);
    }
}

StorIO is not one of black magic libs/frameworks, just write your code which uses StorIO as your normal code :)

@dimsuz
Copy link

dimsuz commented Aug 20, 2015

Oh, that's a nice hint, thanks!
Still feeling a little weird about joins requiring raw query (after wow-effect of other StorIO api), but your are right, this would require some black magic to support using fluent API and some tradeoffs would likely need to be made and this is the thing which everyone is struggling with when using ORMs :)

@artem-zinnatullin
Copy link
Member

Still feeling a little weird about joins requiring raw query

It's just because StorIO is not ORM and will never be it (I hope :))

@dimsuz
Copy link

dimsuz commented Aug 20, 2015

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants