diff --git a/schemas/im.conversations.android.database.ConversationsDatabase/1.json b/schemas/im.conversations.android.database.ConversationsDatabase/1.json index 7c25642ed..ca6b562e6 100644 --- a/schemas/im.conversations.android.database.ConversationsDatabase/1.json +++ b/schemas/im.conversations.android.database.ConversationsDatabase/1.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 1, - "identityHash": "aa5e73a1cf9ba959e118f66b89b9d227", + "identityHash": "afc5b1df44123031e340e1a3db15396d", "entities": [ { "tableName": "account", @@ -106,10 +106,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -148,10 +148,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -215,10 +215,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -248,7 +248,7 @@ }, { "tableName": "disco", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `capsHash` BLOB, `caps2Hash` BLOB, `caps2Algorithm` TEXT, `accountId` INTEGER NOT NULL, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `capsHash` BLOB, `caps2Hash` BLOB, `caps2Algorithm` TEXT, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "fields": [ { "fieldPath": "id", @@ -256,6 +256,12 @@ "affinity": "INTEGER", "notNull": false }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, { "fieldPath": "capsHash", "columnName": "capsHash", @@ -273,19 +279,13 @@ "columnName": "caps2Algorithm", "affinity": "TEXT", "notNull": false - }, - { - "fieldPath": "accountId", - "columnName": "accountId", - "affinity": "INTEGER", - "notNull": true } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -330,10 +330,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -384,10 +384,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -438,10 +438,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -492,10 +492,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -558,10 +558,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -588,6 +588,110 @@ } ] }, + { + "tableName": "disco_item", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `node` TEXT, `parent` TEXT, `discoId` INTEGER, FOREIGN KEY(`accountId`) REFERENCES `account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE , FOREIGN KEY(`discoId`) REFERENCES `disco`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "accountId", + "columnName": "accountId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "node", + "columnName": "node", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parent", + "columnName": "parent", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "discoId", + "columnName": "discoId", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_disco_item_accountId_address_node", + "unique": true, + "columnNames": [ + "accountId", + "address", + "node" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_disco_item_accountId_address_node` ON `${TABLE_NAME}` (`accountId`, `address`, `node`)" + }, + { + "name": "index_disco_item_accountId_parent", + "unique": false, + "columnNames": [ + "accountId", + "parent" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_disco_item_accountId_parent` ON `${TABLE_NAME}` (`accountId`, `parent`)" + }, + { + "name": "index_disco_item_discoId", + "unique": false, + "columnNames": [ + "discoId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_disco_item_discoId` ON `${TABLE_NAME}` (`discoId`)" + } + ], + "foreignKeys": [ + { + "table": "account", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "accountId" + ], + "referencedColumns": [ + "id" + ] + }, + { + "table": "disco", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "discoId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, { "tableName": "message", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `chatId` INTEGER NOT NULL, `receivedAt` INTEGER, `sentAt` INTEGER, `bareTo` TEXT, `toResource` TEXT, `bareFrom` TEXT, `fromResource` TEXT, `occupantId` TEXT, `messageId` TEXT, `stanzaId` TEXT, `acknowledged` INTEGER NOT NULL, FOREIGN KEY(`chatId`) REFERENCES `chat`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", @@ -666,10 +770,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -738,10 +842,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -828,10 +932,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -942,10 +1046,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -1034,10 +1138,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -1106,10 +1210,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -1161,10 +1265,10 @@ } ], "primaryKey": { + "autoGenerate": true, "columnNames": [ "id" - ], - "autoGenerate": true + ] }, "indices": [ { @@ -1195,7 +1299,7 @@ "views": [], "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, 'aa5e73a1cf9ba959e118f66b89b9d227')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'afc5b1df44123031e340e1a3db15396d')" ] } } \ No newline at end of file diff --git a/src/main/java/im/conversations/android/database/ConversationsDatabase.java b/src/main/java/im/conversations/android/database/ConversationsDatabase.java index 58eb4e3c0..a5e96dd75 100644 --- a/src/main/java/im/conversations/android/database/ConversationsDatabase.java +++ b/src/main/java/im/conversations/android/database/ConversationsDatabase.java @@ -7,6 +7,7 @@ import androidx.room.RoomDatabase; import androidx.room.TypeConverters; import im.conversations.android.database.dao.AccountDao; import im.conversations.android.database.dao.BlockingDao; +import im.conversations.android.database.dao.DiscoDao; import im.conversations.android.database.dao.MessageDao; import im.conversations.android.database.dao.PresenceDao; import im.conversations.android.database.dao.RosterDao; @@ -19,6 +20,7 @@ import im.conversations.android.database.entity.DiscoExtensionFieldEntity; import im.conversations.android.database.entity.DiscoExtensionFieldValueEntity; import im.conversations.android.database.entity.DiscoFeatureEntity; import im.conversations.android.database.entity.DiscoIdentityEntity; +import im.conversations.android.database.entity.DiscoItemEntity; import im.conversations.android.database.entity.MessageEntity; import im.conversations.android.database.entity.MessagePartEntity; import im.conversations.android.database.entity.MessageVersionEntity; @@ -38,6 +40,7 @@ import im.conversations.android.database.entity.RosterItemGroupEntity; DiscoExtensionFieldValueEntity.class, DiscoFeatureEntity.class, DiscoIdentityEntity.class, + DiscoItemEntity.class, MessageEntity.class, MessagePartEntity.class, MessageVersionEntity.class, @@ -70,11 +73,13 @@ public abstract class ConversationsDatabase extends RoomDatabase { public abstract AccountDao accountDao(); - public abstract PresenceDao presenceDao(); + public abstract BlockingDao blockingDao(); + + public abstract DiscoDao discoDao(); public abstract MessageDao messageDao(); - public abstract RosterDao rosterDao(); + public abstract PresenceDao presenceDao(); - public abstract BlockingDao blockingDao(); + public abstract RosterDao rosterDao(); } diff --git a/src/main/java/im/conversations/android/database/dao/DiscoDao.java b/src/main/java/im/conversations/android/database/dao/DiscoDao.java new file mode 100644 index 000000000..f2a9aaf72 --- /dev/null +++ b/src/main/java/im/conversations/android/database/dao/DiscoDao.java @@ -0,0 +1,43 @@ +package im.conversations.android.database.dao; + +import androidx.room.Dao; +import androidx.room.Transaction; +import androidx.room.Upsert; +import com.google.common.collect.Collections2; +import eu.siacs.conversations.xmpp.Jid; +import im.conversations.android.database.entity.DiscoItemEntity; +import im.conversations.android.database.model.Account; +import im.conversations.android.xmpp.model.disco.items.Item; +import java.util.Collection; + +@Dao +public abstract class DiscoDao { + + @Upsert(entity = DiscoItemEntity.class) + protected abstract void setDiscoItems(Collection items); + + @Transaction + public void setDiscoItems( + final Account account, final Jid parent, final Collection items) { + final var entities = + Collections2.transform(items, i -> DiscoItemWithParent.of(account.id, parent, i)); + setDiscoItems(entities); + } + + public static class DiscoItemWithParent { + public long accountId; + public Jid address; + public String node; + public Jid parent; + + public static DiscoItemWithParent of( + final long account, final Jid parent, final Item item) { + final var entity = new DiscoItemWithParent(); + entity.accountId = account; + entity.address = item.getJid(); + entity.node = item.getNode(); + entity.parent = parent; + return entity; + } + } +} diff --git a/src/main/java/im/conversations/android/database/entity/DiscoItemEntity.java b/src/main/java/im/conversations/android/database/entity/DiscoItemEntity.java index 5d386c1cf..363dc1441 100644 --- a/src/main/java/im/conversations/android/database/entity/DiscoItemEntity.java +++ b/src/main/java/im/conversations/android/database/entity/DiscoItemEntity.java @@ -24,11 +24,12 @@ import eu.siacs.conversations.xmpp.Jid; }, indices = { @Index( - value = {"accountId", "address"}, + value = {"accountId", "address", "node"}, unique = true), @Index( value = {"accountId", "parent"}, - unique = false) + unique = false), + @Index(value = {"discoId"}) }) public class DiscoItemEntity { @@ -39,6 +40,8 @@ public class DiscoItemEntity { @NonNull Jid address; + @Nullable public String node; + @Nullable public Jid parent; public Long discoId; diff --git a/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java b/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java index ec293f696..94c34f8cc 100644 --- a/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java +++ b/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java @@ -1,6 +1,7 @@ package im.conversations.android.xmpp.manager; import android.content.Context; +import com.google.common.collect.Collections2; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -11,6 +12,7 @@ import im.conversations.android.xmpp.model.disco.info.InfoQuery; import im.conversations.android.xmpp.model.disco.items.Item; import im.conversations.android.xmpp.model.disco.items.ItemsQuery; import java.util.Collection; +import java.util.Objects; public class DiscoManager extends AbstractManager { @@ -48,9 +50,11 @@ public class DiscoManager extends AbstractManager { if (itemsQuery == null) { throw new IllegalStateException(); } - // TODO store items final var items = itemsQuery.getExtensions(Item.class); - return items; + final var validItems = + Collections2.filter(items, i -> Objects.nonNull(i.getJid())); + getDatabase().discoDao().setDiscoItems(getAccount(), entity, validItems); + return validItems; }, MoreExecutors.directExecutor()); }