remove unneeded instance id from db cache (#1035)

* remove unneeded instance id from db cache

* fix TimelineDAOTest

* fix TimelineRepositoryTest
main
Konrad Pozniak 6 years ago committed by GitHub
parent c3fc97a12f
commit 62824c602a
  1. 656
      app/schemas/com.keylesspalace.tusky.db.AppDatabase/13.json
  2. 4
      app/src/androidTest/java/com/keylesspalace/tusky/TimelineDAOTest.kt
  3. 2
      app/src/main/java/com/keylesspalace/tusky/TuskyApplication.java
  4. 59
      app/src/main/java/com/keylesspalace/tusky/db/AppDatabase.java
  5. 6
      app/src/main/java/com/keylesspalace/tusky/db/TimelineDao.kt
  6. 2
      app/src/main/java/com/keylesspalace/tusky/db/TimelineStatusEntity.kt
  7. 23
      app/src/main/java/com/keylesspalace/tusky/repository/TimelineRepository.kt
  8. 24
      app/src/test/java/com/keylesspalace/tusky/fragment/TimelineRepositoryTest.kt

@ -0,0 +1,656 @@
{
"formatVersion": 1,
"database": {
"version": 13,
"identityHash": "9a63a3ab2c05004022c350aab0e472c0",
"entities": [
{
"tableName": "TootEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `text` TEXT, `urls` TEXT, `descriptions` TEXT, `contentWarning` TEXT, `inReplyToId` TEXT, `inReplyToText` TEXT, `inReplyToUsername` TEXT, `visibility` INTEGER)",
"fields": [
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "text",
"columnName": "text",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "urls",
"columnName": "urls",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "descriptions",
"columnName": "descriptions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "contentWarning",
"columnName": "contentWarning",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "inReplyToId",
"columnName": "inReplyToId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "inReplyToText",
"columnName": "inReplyToText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "inReplyToUsername",
"columnName": "inReplyToUsername",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"uid"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "AccountEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `domain` TEXT NOT NULL, `accessToken` TEXT NOT NULL, `isActive` INTEGER NOT NULL, `accountId` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `profilePictureUrl` TEXT NOT NULL, `notificationsEnabled` INTEGER NOT NULL, `notificationsMentioned` INTEGER NOT NULL, `notificationsFollowed` INTEGER NOT NULL, `notificationsReblogged` INTEGER NOT NULL, `notificationsFavorited` INTEGER NOT NULL, `notificationSound` INTEGER NOT NULL, `notificationVibration` INTEGER NOT NULL, `notificationLight` INTEGER NOT NULL, `defaultPostPrivacy` INTEGER NOT NULL, `defaultMediaSensitivity` INTEGER NOT NULL, `alwaysShowSensitiveMedia` INTEGER NOT NULL, `mediaPreviewEnabled` INTEGER NOT NULL, `lastNotificationId` TEXT NOT NULL, `activeNotifications` TEXT NOT NULL, `emojis` TEXT NOT NULL, `tabPreferences` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "domain",
"columnName": "domain",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "accessToken",
"columnName": "accessToken",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isActive",
"columnName": "isActive",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accountId",
"columnName": "accountId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "profilePictureUrl",
"columnName": "profilePictureUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "notificationsEnabled",
"columnName": "notificationsEnabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationsMentioned",
"columnName": "notificationsMentioned",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationsFollowed",
"columnName": "notificationsFollowed",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationsReblogged",
"columnName": "notificationsReblogged",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationsFavorited",
"columnName": "notificationsFavorited",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationSound",
"columnName": "notificationSound",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationVibration",
"columnName": "notificationVibration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "notificationLight",
"columnName": "notificationLight",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "defaultPostPrivacy",
"columnName": "defaultPostPrivacy",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "defaultMediaSensitivity",
"columnName": "defaultMediaSensitivity",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "alwaysShowSensitiveMedia",
"columnName": "alwaysShowSensitiveMedia",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "mediaPreviewEnabled",
"columnName": "mediaPreviewEnabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastNotificationId",
"columnName": "lastNotificationId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "activeNotifications",
"columnName": "activeNotifications",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "emojis",
"columnName": "emojis",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tabPreferences",
"columnName": "tabPreferences",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [
{
"name": "index_AccountEntity_domain_accountId",
"unique": true,
"columnNames": [
"domain",
"accountId"
],
"createSql": "CREATE UNIQUE INDEX `index_AccountEntity_domain_accountId` ON `${TABLE_NAME}` (`domain`, `accountId`)"
}
],
"foreignKeys": []
},
{
"tableName": "InstanceEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`instance` TEXT NOT NULL, `emojiList` TEXT, `maximumTootCharacters` INTEGER, PRIMARY KEY(`instance`))",
"fields": [
{
"fieldPath": "instance",
"columnName": "instance",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "emojiList",
"columnName": "emojiList",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "maximumTootCharacters",
"columnName": "maximumTootCharacters",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"instance"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "TimelineStatusEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `url` TEXT, `timelineUserId` INTEGER NOT NULL, `authorServerId` TEXT, `inReplyToId` TEXT, `inReplyToAccountId` TEXT, `content` TEXT, `createdAt` INTEGER NOT NULL, `emojis` TEXT, `reblogsCount` INTEGER NOT NULL, `favouritesCount` INTEGER NOT NULL, `reblogged` INTEGER NOT NULL, `favourited` INTEGER NOT NULL, `sensitive` INTEGER NOT NULL, `spoilerText` TEXT, `visibility` INTEGER, `attachments` TEXT, `mentions` TEXT, `application` TEXT, `reblogServerId` TEXT, `reblogAccountId` TEXT, PRIMARY KEY(`serverId`, `timelineUserId`), FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "timelineUserId",
"columnName": "timelineUserId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "authorServerId",
"columnName": "authorServerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "inReplyToId",
"columnName": "inReplyToId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "inReplyToAccountId",
"columnName": "inReplyToAccountId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "content",
"columnName": "content",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "createdAt",
"columnName": "createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "emojis",
"columnName": "emojis",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "reblogsCount",
"columnName": "reblogsCount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favouritesCount",
"columnName": "favouritesCount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "reblogged",
"columnName": "reblogged",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "favourited",
"columnName": "favourited",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "sensitive",
"columnName": "sensitive",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "spoilerText",
"columnName": "spoilerText",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "visibility",
"columnName": "visibility",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "attachments",
"columnName": "attachments",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "mentions",
"columnName": "mentions",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "application",
"columnName": "application",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "reblogServerId",
"columnName": "reblogServerId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "reblogAccountId",
"columnName": "reblogAccountId",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"serverId",
"timelineUserId"
],
"autoGenerate": false
},
"indices": [
{
"name": "index_TimelineStatusEntity_authorServerId_timelineUserId",
"unique": false,
"columnNames": [
"authorServerId",
"timelineUserId"
],
"createSql": "CREATE INDEX `index_TimelineStatusEntity_authorServerId_timelineUserId` ON `${TABLE_NAME}` (`authorServerId`, `timelineUserId`)"
}
],
"foreignKeys": [
{
"table": "TimelineAccountEntity",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"authorServerId",
"timelineUserId"
],
"referencedColumns": [
"serverId",
"timelineUserId"
]
}
]
},
{
"tableName": "TimelineAccountEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`serverId` TEXT NOT NULL, `timelineUserId` INTEGER NOT NULL, `localUsername` TEXT NOT NULL, `username` TEXT NOT NULL, `displayName` TEXT NOT NULL, `url` TEXT NOT NULL, `avatar` TEXT NOT NULL, `emojis` TEXT NOT NULL, PRIMARY KEY(`serverId`, `timelineUserId`))",
"fields": [
{
"fieldPath": "serverId",
"columnName": "serverId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "timelineUserId",
"columnName": "timelineUserId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "localUsername",
"columnName": "localUsername",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "avatar",
"columnName": "avatar",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "emojis",
"columnName": "emojis",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"serverId",
"timelineUserId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "ConversationEntity",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`accountId` INTEGER NOT NULL, `id` TEXT NOT NULL, `accounts` TEXT NOT NULL, `unread` INTEGER NOT NULL, `s_id` TEXT NOT NULL, `s_url` TEXT, `s_inReplyToId` TEXT, `s_inReplyToAccountId` TEXT, `s_account` TEXT NOT NULL, `s_content` TEXT NOT NULL, `s_createdAt` INTEGER NOT NULL, `s_emojis` TEXT NOT NULL, `s_favouritesCount` INTEGER NOT NULL, `s_favourited` INTEGER NOT NULL, `s_sensitive` INTEGER NOT NULL, `s_spoilerText` TEXT NOT NULL, `s_attachments` TEXT NOT NULL, `s_mentions` TEXT NOT NULL, `s_showingHiddenContent` INTEGER NOT NULL, `s_expanded` INTEGER NOT NULL, `s_collapsible` INTEGER NOT NULL, `s_collapsed` INTEGER NOT NULL, PRIMARY KEY(`id`, `accountId`))",
"fields": [
{
"fieldPath": "accountId",
"columnName": "accountId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "accounts",
"columnName": "accounts",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "unread",
"columnName": "unread",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.id",
"columnName": "s_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.url",
"columnName": "s_url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastStatus.inReplyToId",
"columnName": "s_inReplyToId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastStatus.inReplyToAccountId",
"columnName": "s_inReplyToAccountId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lastStatus.account",
"columnName": "s_account",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.content",
"columnName": "s_content",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.createdAt",
"columnName": "s_createdAt",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.emojis",
"columnName": "s_emojis",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.favouritesCount",
"columnName": "s_favouritesCount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.favourited",
"columnName": "s_favourited",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.sensitive",
"columnName": "s_sensitive",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.spoilerText",
"columnName": "s_spoilerText",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.attachments",
"columnName": "s_attachments",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.mentions",
"columnName": "s_mentions",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastStatus.showingHiddenContent",
"columnName": "s_showingHiddenContent",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.expanded",
"columnName": "s_expanded",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.collapsible",
"columnName": "s_collapsible",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastStatus.collapsed",
"columnName": "s_collapsed",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id",
"accountId"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"9a63a3ab2c05004022c350aab0e472c0\")"
]
}
}

@ -133,7 +133,6 @@ class TimelineDAOTest {
val author = TimelineAccountEntity( val author = TimelineAccountEntity(
authorServerId, authorServerId,
accountId, accountId,
"birb.site",
"localUsername", "localUsername",
"username", "username",
"displayName", "displayName",
@ -146,7 +145,6 @@ class TimelineDAOTest {
TimelineAccountEntity( TimelineAccountEntity(
"R$authorServerId", "R$authorServerId",
accountId, accountId,
"Rbirb.site",
"RlocalUsername", "RlocalUsername",
"Rusername", "Rusername",
"RdisplayName", "RdisplayName",
@ -163,7 +161,6 @@ class TimelineDAOTest {
url = "url$statusId", url = "url$statusId",
timelineUserId = accountId, timelineUserId = accountId,
authorServerId = authorServerId, authorServerId = authorServerId,
instance = "birb.site$statusId",
inReplyToId = "inReplyToId$statusId", inReplyToId = "inReplyToId$statusId",
inReplyToAccountId = "inReplyToAccountId$statusId", inReplyToAccountId = "inReplyToAccountId$statusId",
content = "Content!$statusId", content = "Content!$statusId",
@ -191,7 +188,6 @@ class TimelineDAOTest {
url = null, url = null,
timelineUserId = timelineUserId, timelineUserId = timelineUserId,
authorServerId = null, authorServerId = null,
instance = null,
inReplyToId = null, inReplyToId = null,
inReplyToAccountId = null, inReplyToAccountId = null,
content = null, content = null,

@ -67,7 +67,7 @@ public class TuskyApplication extends Application implements HasActivityInjector
.addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5, .addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5,
AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8, AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8,
AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10, AppDatabase.MIGRATION_10_11, AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10, AppDatabase.MIGRATION_10_11,
AppDatabase.MIGRATION_11_12) AppDatabase.MIGRATION_11_12, AppDatabase.MIGRATION_12_13, AppDatabase.MIGRATION_10_13)
.build(); .build();
accountManager = new AccountManager(appDatabase); accountManager = new AccountManager(appDatabase);
serviceLocator = new ServiceLocator() { serviceLocator = new ServiceLocator() {

@ -30,7 +30,7 @@ import androidx.annotation.NonNull;
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class, @Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class, TimelineStatusEntity.class,
TimelineAccountEntity.class, ConversationEntity.class TimelineAccountEntity.class, ConversationEntity.class
}, version = 12) }, version = 13)
public abstract class AppDatabase extends RoomDatabase { public abstract class AppDatabase extends RoomDatabase {
public abstract TootDao tootDao(); public abstract TootDao tootDao();
@ -207,4 +207,61 @@ public abstract class AppDatabase extends RoomDatabase {
} }
}; };
public static final Migration MIGRATION_12_13 = new Migration(12, 13) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("DROP TABLE IF EXISTS `TimelineAccountEntity`");
database.execSQL("DROP TABLE IF EXISTS `TimelineStatusEntity`");
database.execSQL("CREATE TABLE IF NOT EXISTS `TimelineAccountEntity` (" +
"`serverId` TEXT NOT NULL, " +
"`timelineUserId` INTEGER NOT NULL, " +
"`localUsername` TEXT NOT NULL, " +
"`username` TEXT NOT NULL, " +
"`displayName` TEXT NOT NULL, " +
"`url` TEXT NOT NULL, " +
"`avatar` TEXT NOT NULL, " +
"`emojis` TEXT NOT NULL," +
"PRIMARY KEY(`serverId`, `timelineUserId`))");
database.execSQL("CREATE TABLE IF NOT EXISTS `TimelineStatusEntity` (" +
"`serverId` TEXT NOT NULL, " +
"`url` TEXT, " +
"`timelineUserId` INTEGER NOT NULL, " +
"`authorServerId` TEXT," +
"`inReplyToId` TEXT, " +
"`inReplyToAccountId` TEXT, " +
"`content` TEXT, " +
"`createdAt` INTEGER NOT NULL, " +
"`emojis` TEXT, " +
"`reblogsCount` INTEGER NOT NULL, " +
"`favouritesCount` INTEGER NOT NULL, " +
"`reblogged` INTEGER NOT NULL, " +
"`favourited` INTEGER NOT NULL, " +
"`sensitive` INTEGER NOT NULL, " +
"`spoilerText` TEXT, " +
"`visibility` INTEGER, " +
"`attachments` TEXT, " +
"`mentions` TEXT, " +
"`application` TEXT, " +
"`reblogServerId` TEXT, " +
"`reblogAccountId` TEXT," +
" PRIMARY KEY(`serverId`, `timelineUserId`)," +
" FOREIGN KEY(`authorServerId`, `timelineUserId`) REFERENCES `TimelineAccountEntity`(`serverId`, `timelineUserId`) " +
"ON UPDATE NO ACTION ON DELETE NO ACTION )");
database.execSQL("CREATE INDEX IF NOT EXISTS" +
"`index_TimelineStatusEntity_authorServerId_timelineUserId` " +
"ON `TimelineStatusEntity` (`authorServerId`, `timelineUserId`)");
}
};
public static final Migration MIGRATION_10_13 = new Migration(10, 13) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
MIGRATION_11_12.migrate(database);
MIGRATION_12_13.migrate(database);
}
};
} }

@ -24,14 +24,14 @@ abstract class TimelineDao {
@Query(""" @Query("""
SELECT s.serverId, s.url, s.timelineUserId, SELECT s.serverId, s.url, s.timelineUserId,
s.authorServerId, s.instance, s.inReplyToId, s.inReplyToAccountId, s.createdAt, s.authorServerId, s.inReplyToId, s.inReplyToAccountId, s.createdAt,
s.emojis, s.reblogsCount, s.favouritesCount, s.reblogged, s.favourited, s.sensitive, s.emojis, s.reblogsCount, s.favouritesCount, s.reblogged, s.favourited, s.sensitive,
s.spoilerText, s.visibility, s.mentions, s.application, s.reblogServerId,s.reblogAccountId, s.spoilerText, s.visibility, s.mentions, s.application, s.reblogServerId,s.reblogAccountId,
s.content, s.attachments, s.content, s.attachments,
a.serverId as 'a_serverId', a.timelineUserId as 'a_timelineUserId', a.instance as 'a_instance', a.serverId as 'a_serverId', a.timelineUserId as 'a_timelineUserId',
a.localUsername as 'a_localUsername', a.username as 'a_username', a.localUsername as 'a_localUsername', a.username as 'a_username',
a.displayName as 'a_displayName', a.url as 'a_url', a.avatar as 'a_avatar', a.emojis as 'a_emojis', a.displayName as 'a_displayName', a.url as 'a_url', a.avatar as 'a_avatar', a.emojis as 'a_emojis',
rb.serverId as 'rb_serverId', rb.timelineUserId 'rb_timelineUserId', rb.instance as 'rb_instance', rb.serverId as 'rb_serverId', rb.timelineUserId 'rb_timelineUserId',
rb.localUsername as 'rb_localUsername', rb.username as 'rb_username', rb.localUsername as 'rb_localUsername', rb.username as 'rb_username',
rb.displayName as 'rb_displayName', rb.url as 'rb_url', rb.avatar as 'rb_avatar', rb.displayName as 'rb_displayName', rb.url as 'rb_url', rb.avatar as 'rb_avatar',
rb.emojis as'rb_emojis' rb.emojis as'rb_emojis'

@ -33,7 +33,6 @@ data class TimelineStatusEntity(
// our local id for the logged in user in case there are multiple accounts per instance // our local id for the logged in user in case there are multiple accounts per instance
val timelineUserId: Long, val timelineUserId: Long,
val authorServerId: String?, val authorServerId: String?,
val instance: String?,
val inReplyToId: String?, val inReplyToId: String?,
val inReplyToAccountId: String?, val inReplyToAccountId: String?,
val content: String?, val content: String?,
@ -59,7 +58,6 @@ data class TimelineStatusEntity(
data class TimelineAccountEntity( data class TimelineAccountEntity(
val serverId: String, val serverId: String,
val timelineUserId: Long, val timelineUserId: Long,
val instance: String,
val localUsername: String, val localUsername: String,
val username: String, val username: String,
val displayName: String, val displayName: String,

@ -52,23 +52,21 @@ class TimelineRepositoryImpl(
): Single<out List<TimelineStatus>> { ): Single<out List<TimelineStatus>> {
val acc = accountManager.activeAccount ?: throw IllegalStateException() val acc = accountManager.activeAccount ?: throw IllegalStateException()
val accountId = acc.id val accountId = acc.id
val instance = acc.domain
return if (requestMode == DISK) { return if (requestMode == DISK) {
this.getStatusesFromDb(accountId, maxId, sinceId, limit) this.getStatusesFromDb(accountId, maxId, sinceId, limit)
} else { } else {
getStatusesFromNetwork(maxId, sinceId, sincedIdMinusOne, limit, instance, accountId, getStatusesFromNetwork(maxId, sinceId, sincedIdMinusOne, limit, accountId, requestMode)
requestMode)
} }
} }
private fun getStatusesFromNetwork(maxId: String?, sinceId: String?, private fun getStatusesFromNetwork(maxId: String?, sinceId: String?,
sinceIdMinusOne: String?, limit: Int, instance: String, sinceIdMinusOne: String?, limit: Int,
accountId: Long, requestMode: TimelineRequestMode accountId: Long, requestMode: TimelineRequestMode
): Single<out List<TimelineStatus>> { ): Single<out List<TimelineStatus>> {
return mastodonApi.homeTimelineSingle(maxId, sinceIdMinusOne, limit + 1) return mastodonApi.homeTimelineSingle(maxId, sinceIdMinusOne, limit + 1)
.map { statuses -> .map { statuses ->
this.saveStatusesToDb(instance, accountId, statuses, maxId, sinceId) this.saveStatusesToDb(accountId, statuses, maxId, sinceId)
} }
.flatMap { statuses -> .flatMap { statuses ->
this.addFromDbIfNeeded(accountId, statuses, maxId, sinceId, limit, requestMode) this.addFromDbIfNeeded(accountId, statuses, maxId, sinceId, limit, requestMode)
@ -116,7 +114,7 @@ class TimelineRepositoryImpl(
} }
} }
private fun saveStatusesToDb(instance: String, accountId: Long, statuses: List<Status>, private fun saveStatusesToDb(accountId: Long, statuses: List<Status>,
maxId: String?, sinceId: String? maxId: String?, sinceId: String?
): List<Either<Placeholder, Status>> { ): List<Either<Placeholder, Status>> {
var placeholderToInsert: Placeholder? = null var placeholderToInsert: Placeholder? = null
@ -146,9 +144,9 @@ class TimelineRepositoryImpl(
Single.fromCallable { Single.fromCallable {
for (status in statuses) { for (status in statuses) {
timelineDao.insertInTransaction( timelineDao.insertInTransaction(
status.toEntity(accountId, instance, htmlConverter, gson), status.toEntity(accountId, htmlConverter, gson),
status.account.toEntity(instance, accountId, gson), status.account.toEntity(accountId, gson),
status.reblog?.account?.toEntity(instance, accountId, gson) status.reblog?.account?.toEntity(accountId, gson)
) )
} }
@ -279,11 +277,10 @@ class TimelineRepositoryImpl(
private val emojisListTypeToken = object : TypeToken<List<Emoji>>() {} private val emojisListTypeToken = object : TypeToken<List<Emoji>>() {}
fun Account.toEntity(instance: String, accountId: Long, gson: Gson): TimelineAccountEntity { fun Account.toEntity(accountId: Long, gson: Gson): TimelineAccountEntity {
return TimelineAccountEntity( return TimelineAccountEntity(
serverId = id, serverId = id,
timelineUserId = accountId, timelineUserId = accountId,
instance = instance,
localUsername = localUsername, localUsername = localUsername,
username = username, username = username,
displayName = displayName, displayName = displayName,
@ -320,7 +317,6 @@ fun Placeholder.toEntity(timelineUserId: Long): TimelineStatusEntity {
return TimelineStatusEntity( return TimelineStatusEntity(
serverId = this.id, serverId = this.id,
url = null, url = null,
instance = null,
timelineUserId = timelineUserId, timelineUserId = timelineUserId,
authorServerId = null, authorServerId = null,
inReplyToId = null, inReplyToId = null,
@ -344,14 +340,13 @@ fun Placeholder.toEntity(timelineUserId: Long): TimelineStatusEntity {
) )
} }
fun Status.toEntity(timelineUserId: Long, instance: String, fun Status.toEntity(timelineUserId: Long,
htmlConverter: HtmlConverter, htmlConverter: HtmlConverter,
gson: Gson): TimelineStatusEntity { gson: Gson): TimelineStatusEntity {
val actionable = actionableStatus val actionable = actionableStatus
return TimelineStatusEntity( return TimelineStatusEntity(
serverId = this.id, serverId = this.id,
url = actionable.url!!, url = actionable.url!!,
instance = instance,
timelineUserId = timelineUserId, timelineUserId = timelineUserId,
authorServerId = actionable.account.id, authorServerId = actionable.account.id,
inReplyToId = actionable.inReplyToId, inReplyToId = actionable.inReplyToId,

@ -93,8 +93,8 @@ class TimelineRepositoryTest {
verify(timelineDao).insertStatusIfNotThere(Placeholder("1").toEntity(account.id)) verify(timelineDao).insertStatusIfNotThere(Placeholder("1").toEntity(account.id))
for (status in statuses) { for (status in statuses) {
verify(timelineDao).insertInTransaction( verify(timelineDao).insertInTransaction(
status.toEntity(account.id, account.domain, htmlConverter, gson), status.toEntity(account.id, htmlConverter, gson),
status.account.toEntity(account.domain, account.id, gson), status.account.toEntity(account.id, gson),
null null
) )
} }
@ -124,8 +124,8 @@ class TimelineRepositoryTest {
// We assume for now that overlapped one is inserted but it's not that important // We assume for now that overlapped one is inserted but it's not that important
for (status in response) { for (status in response) {
verify(timelineDao).insertInTransaction( verify(timelineDao).insertInTransaction(
status.toEntity(account.id, account.domain, htmlConverter, gson), status.toEntity(account.id, htmlConverter, gson),
status.account.toEntity(account.domain, account.id, gson), status.account.toEntity(account.id, gson),
null null
) )
} }
@ -153,8 +153,8 @@ class TimelineRepositoryTest {
testScheduler.advanceTimeBy(100, TimeUnit.SECONDS) testScheduler.advanceTimeBy(100, TimeUnit.SECONDS)
for (status in response) { for (status in response) {
verify(timelineDao).insertInTransaction( verify(timelineDao).insertInTransaction(
status.toEntity(account.id, account.domain, htmlConverter, gson), status.toEntity(account.id, htmlConverter, gson),
status.account.toEntity(account.domain, account.id, gson), status.account.toEntity(account.id, gson),
null null
) )
} }
@ -194,8 +194,8 @@ class TimelineRepositoryTest {
// We assume for now that overlapped one is inserted but it's not that important // We assume for now that overlapped one is inserted but it's not that important
for (status in response) { for (status in response) {
verify(timelineDao).insertInTransaction( verify(timelineDao).insertInTransaction(
status.toEntity(account.id, account.domain, htmlConverter, gson), status.toEntity(account.id, htmlConverter, gson),
status.account.toEntity(account.domain, account.id, gson), status.account.toEntity(account.id, gson),
null null
) )
} }
@ -236,8 +236,8 @@ class TimelineRepositoryTest {
// We assume for now that overlapped one is inserted but it's not that important // We assume for now that overlapped one is inserted but it's not that important
for (status in response) { for (status in response) {
verify(timelineDao).insertInTransaction( verify(timelineDao).insertInTransaction(
status.toEntity(account.id, account.domain, htmlConverter, gson), status.toEntity(account.id, htmlConverter, gson),
status.account.toEntity(account.domain, account.id, gson), status.account.toEntity(account.id, gson),
null null
) )
} }
@ -253,8 +253,8 @@ class TimelineRepositoryTest {
val status = makeStatus("2") val status = makeStatus("2")
val dbStatus = makeStatus("1") val dbStatus = makeStatus("1")
val dbResult = TimelineStatusWithAccount() val dbResult = TimelineStatusWithAccount()
dbResult.status = dbStatus.toEntity(account.id, account.domain, htmlConverter, gson) dbResult.status = dbStatus.toEntity(account.id, htmlConverter, gson)
dbResult.account = status.account.toEntity(account.domain, account.id, gson) dbResult.account = status.account.toEntity(account.id, gson)
whenever(mastodonApi.homeTimelineSingle(any(), any(), any())) whenever(mastodonApi.homeTimelineSingle(any(), any(), any()))
.thenReturn(Single.just(listOf(status))) .thenReturn(Single.just(listOf(status)))

Loading…
Cancel
Save