Closed TheRishka closed 9 years ago
Sure, you are second person who asks this, I'd work on it today/tomorrow.
Please also add me.
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.
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);
}
}
Please also lists. I'm thinking about using StorIO instead of an orm-lib.
@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?
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.
@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 :)
@dimsuz why you can not reuse StorIO methods in mapFromCursor()
? You can make custom query
but reuse type-mapping :)
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 :)
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 :)
So you are saying that the way to do this would be to store reference in resolver field and use it in mapFromCursor?
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 GetResolver
s 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 :)
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 :)
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 :))
:+1:
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!