From 468ff87f247b074af26ddb8b5a0d447d3c5fb8bf Mon Sep 17 00:00:00 2001
From: Artem Zinnatullin <artem.zinnatullin@gmail.com>
Date: Thu, 28 Jan 2016 03:52:54 +0300
Subject: [PATCH] Fix Relations in sample app (JOIN column names collision)

---
 .../pushtorefresh/storio/sample/AppComponent.java  |  5 ++-
 .../pushtorefresh/storio/sample/db/DbModule.java   |  4 +-
 .../storio/sample/db/entities/TweetWithUser.java   | 26 ++++++++++++
 .../storio/sample/db/entities/User.java            | 26 ++++++++++++
 .../db/resolvers/TweetWithUserGetResolver.java     | 13 +++---
 .../storio/sample/db/tables/TweetsTable.java       |  6 ++-
 .../storio/sample/db/tables/UsersTable.java        |  6 +++
 .../storio/sample/sample_code/Relations.java       | 35 ++++++++++++++--
 .../storio/sample/ui/fragment/TweetsFragment.java  |  2 +
 .../storio/sample/sample_code/RelationsTest.java   | 49 ++++++++++++++++++++++
 10 files changed, 156 insertions(+), 16 deletions(-)
 create mode 100644 storio-sample-app/src/test/java/com/pushtorefresh/storio/sample/sample_code/RelationsTest.java

diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/AppComponent.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/AppComponent.java
index b32ddca..979c9e2 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/AppComponent.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/AppComponent.java
@@ -5,6 +5,7 @@
 import com.pushtorefresh.storio.sample.db.DbModule;
 import com.pushtorefresh.storio.sample.provider.SampleContentProvider;
 import com.pushtorefresh.storio.sample.ui.fragment.TweetsFragment;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
 
 import javax.inject.Singleton;
 
@@ -19,6 +20,8 @@
 )
 public interface AppComponent {
     void inject(@NonNull TweetsFragment fragment);
-
     void inject(@NonNull SampleContentProvider sampleContentProvider);
+
+    @NonNull
+    StorIOSQLite storIOSQLite();
 }
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/DbModule.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/DbModule.java
index 429b791..6ff36da 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/DbModule.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/DbModule.java
@@ -35,8 +35,8 @@
     public StorIOSQLite provideStorIOSQLite(@NonNull SQLiteOpenHelper sqLiteOpenHelper) {
         return DefaultStorIOSQLite.builder()
                 .sqliteOpenHelper(sqLiteOpenHelper)
-.addTypeMapping(Tweet.class, new TweetSQLiteTypeMapping())
-.addTypeMapping(User.class, new UserSQLiteTypeMapping())
+                .addTypeMapping(Tweet.class, new TweetSQLiteTypeMapping())
+                .addTypeMapping(User.class, new UserSQLiteTypeMapping())
                 .addTypeMapping(TweetWithUser.class, SQLiteTypeMapping.<TweetWithUser>builder()
                         .putResolver(new TweetWithUserPutResolver())
                         .getResolver(new TweetWithUserGetResolver())
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/TweetWithUser.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/TweetWithUser.java
index 26c8f08..7d2e52a 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/TweetWithUser.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/TweetWithUser.java
@@ -30,4 +30,30 @@ public Tweet tweet() {
     public User user() {
         return user;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TweetWithUser that = (TweetWithUser) o;
+
+        if (!tweet.equals(that.tweet)) return false;
+        return user.equals(that.user);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = tweet.hashCode();
+        result = 31 * result + user.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "TweetWithUser{" +
+                "tweet=" + tweet +
+                ", user=" + user +
+                '}';
+    }
 }
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/User.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/User.java
index e30e532..4e0218f 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/User.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entities/User.java
@@ -47,4 +47,30 @@ public Long id() {
     public String nick() {
         return nick;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        User user = (User) o;
+
+        if (id != null ? !id.equals(user.id) : user.id != null) return false;
+        return nick.equals(user.nick);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id != null ? id.hashCode() : 0;
+        result = 31 * result + nick.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" +
+                "id=" + id +
+                ", nick='" + nick + '\'' +
+                '}';
+    }
 }
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/resolvers/TweetWithUserGetResolver.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/resolvers/TweetWithUserGetResolver.java
index be31094..f07cd74 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/resolvers/TweetWithUserGetResolver.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/resolvers/TweetWithUserGetResolver.java
@@ -7,8 +7,7 @@
 import com.pushtorefresh.storio.sample.db.entities.Tweet;
 import com.pushtorefresh.storio.sample.db.entities.TweetWithUser;
 import com.pushtorefresh.storio.sample.db.entities.User;
-import com.pushtorefresh.storio.sample.db.tables.TweetsTable;
-import com.pushtorefresh.storio.sample.db.tables.UsersTable;
+import com.pushtorefresh.storio.sample.sample_code.Relations;
 import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
 
 public class TweetWithUserGetResolver extends DefaultGetResolver<TweetWithUser> {
@@ -18,14 +17,14 @@
     @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))
+                cursor.getLong(cursor.getColumnIndexOrThrow(Relations.QUERY_COLUMN_TWEET_ID)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Relations.QUERY_COLUMN_TWEET_AUTHOR)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Relations.QUERY_COLUMN_TWEET_CONTENT))
         );
 
         final User user = User.newUser(
-                cursor.getLong(cursor.getColumnIndexOrThrow(UsersTable.COLUMN_ID)),
-                cursor.getString(cursor.getColumnIndexOrThrow(UsersTable.COLUMN_NICK))
+                cursor.getLong(cursor.getColumnIndexOrThrow(Relations.QUERY_COLUMN_USER_ID)),
+                cursor.getString(cursor.getColumnIndexOrThrow(Relations.QUERY_COLUMN_USER_NICK))
         );
 
         return new TweetWithUser(tweet, user);
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/TweetsTable.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/TweetsTable.java
index 3e98a73..e626f0b 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/TweetsTable.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/TweetsTable.java
@@ -26,6 +26,10 @@
     @NonNull
     public static final String COLUMN_CONTENT = "content";
 
+    public static final String COLUMN_ID_WITH_TABLE_PREFIX = TABLE + "." + COLUMN_ID;
+    public static final String COLUMN_AUTHOR_WITH_TABLE_PREFIX = TABLE + "." + COLUMN_AUTHOR;
+    public static final String COLUMN_CONTENT_WITH_TABLE_PREFIX = TABLE + "." + COLUMN_CONTENT;
+
     // Yep, with StorIO you can safely store queries as objects and reuse them, they are immutable
     @NonNull
     public static final Query QUERY_ALL = Query.builder()
@@ -37,8 +41,6 @@ private TweetsTable() {
         throw new IllegalStateException("No instances please");
     }
 
-    // Better than static final field -> allows VM to unload useless String
-    // Because you need this string only once per application life on the device
     @NonNull
     public static String getCreateTableQuery() {
         return "CREATE TABLE " + TABLE + "("
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/UsersTable.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/UsersTable.java
index 3ed42c9..f46f34d 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/UsersTable.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/tables/UsersTable.java
@@ -15,6 +15,12 @@
     @NonNull
     public static final String COLUMN_NICK = "nick";
 
+    @NonNull
+    public static final String COLUMN_ID_WITH_TABLE_PREFIX = TABLE + "." + COLUMN_ID;
+
+    @NonNull
+    public static final String COLUMN_NICK_WITH_TABLE_PREFIX = TABLE + "." + COLUMN_NICK;
+
     // This is just class with Meta Data, we don't need instances
     private UsersTable() {
         throw new IllegalStateException("No instances please");
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/sample_code/Relations.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/sample_code/Relations.java
index d0888af..8bfd372 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/sample_code/Relations.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/sample_code/Relations.java
@@ -16,21 +16,48 @@
 public class Relations {
 
     @NonNull
+    public static final String QUERY_COLUMN_TWEET_ID = "tweet_id";
+
+    @NonNull
+    public static final String QUERY_COLUMN_TWEET_AUTHOR = "tweet_author";
+
+    @NonNull
+    public static final String QUERY_COLUMN_TWEET_CONTENT = "tweet_content";
+
+    @NonNull
+    public static final String QUERY_COLUMN_USER_ID = "user_id";
+
+    @NonNull
+    public static final String QUERY_COLUMN_USER_NICK = "user_nick";
+
+    @NonNull
     private final StorIOSQLite storIOSQLite;
 
     public Relations(@NonNull StorIOSQLite storIOSQLite) {
         this.storIOSQLite = storIOSQLite;
     }
 
-    public List<TweetWithUser> tweetWithUserGet() {
+    @NonNull
+    public List<TweetWithUser> getTweetWithUser() {
         return storIOSQLite
                 .get()
                 .listOfObjects(TweetWithUser.class)
                 .withQuery(RawQuery.builder()
-                        .query("SELECT * FROM " + TweetsTable.TABLE
+                        .query("SELECT "
+                                // Unfortunately we have columns with same names, so we need to give them aliases.
+                                + TweetsTable.COLUMN_ID_WITH_TABLE_PREFIX + " AS \"" + QUERY_COLUMN_TWEET_ID + "\""
+                                + ", "
+                                + TweetsTable.COLUMN_AUTHOR_WITH_TABLE_PREFIX + " AS \"" + QUERY_COLUMN_TWEET_AUTHOR + "\""
+                                + ", "
+                                + TweetsTable.COLUMN_CONTENT_WITH_TABLE_PREFIX + " AS \"" + QUERY_COLUMN_TWEET_CONTENT + "\""
+                                + ", "
+                                + UsersTable.COLUMN_ID_WITH_TABLE_PREFIX + " AS \"" + QUERY_COLUMN_USER_ID + "\""
+                                + ", "
+                                + UsersTable.COLUMN_NICK_WITH_TABLE_PREFIX + " AS \"" + QUERY_COLUMN_USER_NICK + "\""
+                                + " FROM " + TweetsTable.TABLE
                                 + " JOIN " + UsersTable.TABLE
-                                + " ON " + TweetsTable.TABLE + "." + TweetsTable.COLUMN_AUTHOR
-                                + " = " + UsersTable.TABLE + "." + UsersTable.COLUMN_NICK)
+                                + " ON " + TweetsTable.COLUMN_AUTHOR_WITH_TABLE_PREFIX
+                                + " = " + UsersTable.COLUMN_NICK_WITH_TABLE_PREFIX)
                         .build())
                 .prepare()
                 .executeAsBlocking();
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
index 31b4aae..4ef576d 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
@@ -14,6 +14,7 @@
 import com.pushtorefresh.storio.sample.SampleApp;
 import com.pushtorefresh.storio.sample.db.entities.Tweet;
 import com.pushtorefresh.storio.sample.db.tables.TweetsTable;
+import com.pushtorefresh.storio.sample.sample_code.Relations;
 import com.pushtorefresh.storio.sample.ui.DividerItemDecoration;
 import com.pushtorefresh.storio.sample.ui.UiStateController;
 import com.pushtorefresh.storio.sample.ui.adapter.TweetsAdapter;
@@ -56,6 +57,7 @@ public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         SampleApp.get(getActivity()).appComponent().inject(this);
         tweetsAdapter = new TweetsAdapter();
+        new Relations(storIOSQLite).getTweetWithUser();
     }
 
     @Override
diff --git a/storio-sample-app/src/test/java/com/pushtorefresh/storio/sample/sample_code/RelationsTest.java b/storio-sample-app/src/test/java/com/pushtorefresh/storio/sample/sample_code/RelationsTest.java
new file mode 100644
index 0000000..d273813
--- /dev/null
+++ b/storio-sample-app/src/test/java/com/pushtorefresh/storio/sample/sample_code/RelationsTest.java
@@ -0,0 +1,49 @@
+package com.pushtorefresh.storio.sample.sample_code;
+
+import com.pushtorefresh.storio.contentresolver.BuildConfig;
+import com.pushtorefresh.storio.sample.SampleApp;
+import com.pushtorefresh.storio.sample.db.entities.Tweet;
+import com.pushtorefresh.storio.sample.db.entities.TweetWithUser;
+import com.pushtorefresh.storio.sample.db.entities.User;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(RobolectricGradleTestRunner.class)
+@Config(constants = BuildConfig.class, sdk = 21)
+public class RelationsTest {
+
+    @Test
+    public void name() {
+        SampleApp sampleApp = (SampleApp) RuntimeEnvironment.application;
+
+        sampleApp.appComponent().storIOSQLite()
+                .put()
+                .objects(asList(
+                        Tweet.newTweet(1L, "artem_zin", "test tweet 1"),
+                        Tweet.newTweet(2L, "artem_zin", "test tweet 2"),
+                        Tweet.newTweet(3L, "nikitin-da", "test tweet 3"),
+                        User.newUser(1L, "artem_zin"),
+                        User.newUser(2L, "nikitin-da"))
+                )
+                .prepare()
+                .executeAsBlocking();
+
+        Relations relations = new Relations(sampleApp.appComponent().storIOSQLite());
+        List<TweetWithUser> tweetsWithUsers = relations.getTweetWithUser();
+
+        assertThat(tweetsWithUsers).hasSize(3); // Same as count of tweets, not users.
+
+        assertThat(tweetsWithUsers.get(0)).isEqualTo(new TweetWithUser(Tweet.newTweet(1L, "artem_zin", "test tweet 1"), User.newUser(1L, "artem_zin")));
+        assertThat(tweetsWithUsers.get(1)).isEqualTo(new TweetWithUser(Tweet.newTweet(2L, "artem_zin", "test tweet 2"), User.newUser(1L, "artem_zin")));
+        assertThat(tweetsWithUsers.get(2)).isEqualTo(new TweetWithUser(Tweet.newTweet(3L, "nikitin-da", "test tweet 3"), User.newUser(2L, "nikitin-da")));
+    }
+}
\ No newline at end of file
