get rid of upsert in favor of update and insert
upsert seems to only work with primary keys and not other unique constraints.
This commit is contained in:
parent
de06bfb8f0
commit
359ef330df
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "b28e01dcbb5d9774a4b36783d0db6c73",
|
||||
"identityHash": "8f1d4d8d2bdb8b2358132202037aba7a",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "account",
|
||||
|
@ -601,7 +601,7 @@
|
|||
},
|
||||
{
|
||||
"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 NOT NULL, `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 )",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `accountId` INTEGER NOT NULL, `address` TEXT NOT NULL, `node` TEXT NOT NULL, `parent` TEXT NOT NULL, `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",
|
||||
|
@ -631,7 +631,7 @@
|
|||
"fieldPath": "parent",
|
||||
"columnName": "parent",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "discoId",
|
||||
|
@ -648,15 +648,16 @@
|
|||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_disco_item_accountId_address_node",
|
||||
"name": "index_disco_item_accountId_address_node_parent",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"accountId",
|
||||
"address",
|
||||
"node"
|
||||
"node",
|
||||
"parent"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_disco_item_accountId_address_node` ON `${TABLE_NAME}` (`accountId`, `address`, `node`)"
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_disco_item_accountId_address_node_parent` ON `${TABLE_NAME}` (`accountId`, `address`, `node`, `parent`)"
|
||||
},
|
||||
{
|
||||
"name": "index_disco_item_accountId_parent",
|
||||
|
@ -1336,7 +1337,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, 'b28e01dcbb5d9774a4b36783d0db6c73')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8f1d4d8d2bdb8b2358132202037aba7a')"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import androidx.room.Insert;
|
|||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
import im.conversations.android.database.entity.AccountEntity;
|
||||
import im.conversations.android.database.model.Account;
|
||||
import im.conversations.android.database.model.Connection;
|
||||
|
@ -13,12 +14,18 @@ import java.util.List;
|
|||
@Dao
|
||||
public interface AccountDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
void insert(final AccountEntity account);
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
long insert(final AccountEntity account);
|
||||
|
||||
@Query("SELECT id,address,randomSeed FROM account WHERE enabled = 1")
|
||||
ListenableFuture<List<Account>> getEnabledAccounts();
|
||||
|
||||
@Query("SELECT id,address,randomSeed FROM account WHERE address=:address AND enabled=1")
|
||||
ListenableFuture<Account> getEnabledAccount(Jid address);
|
||||
|
||||
@Query("SELECT id,address,randomSeed FROM account WHERE id=:id AND enabled=1")
|
||||
ListenableFuture<Account> getEnabledAccount(long id);
|
||||
|
||||
@Query("SELECT hostname,port,directTls FROM account WHERE id=:id AND hostname != null")
|
||||
Connection getConnectionSettings(long id);
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package im.conversations.android.database.dao;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.OnConflictStrategy;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Transaction;
|
||||
import androidx.room.Upsert;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Collections2;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
|
@ -32,8 +31,11 @@ import java.util.Collection;
|
|||
@Dao
|
||||
public abstract class DiscoDao {
|
||||
|
||||
@Upsert(entity = DiscoItemEntity.class)
|
||||
protected abstract void insertDiscoItems(Collection<DiscoItemWithParent> items);
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
protected abstract void insertDiscoItems(Collection<DiscoItemEntity> items);
|
||||
|
||||
@Insert
|
||||
protected abstract void insert(DiscoItemEntity item);
|
||||
|
||||
@Insert
|
||||
protected abstract void insertDiscoIdentities(Collection<DiscoIdentityEntity> identities);
|
||||
|
@ -53,13 +55,16 @@ public abstract class DiscoDao {
|
|||
protected abstract void updateDiscoIdInPresence(
|
||||
long account, Jid address, String resource, long discoId);
|
||||
|
||||
@Query(
|
||||
"UPDATE disco_item SET discoId=:discoId WHERE accountId=:account AND address=:address"
|
||||
+ " AND node=:node")
|
||||
protected abstract int updateDiscoIdInDiscoItem(
|
||||
long account, Jid address, String node, long discoId);
|
||||
|
||||
@Insert
|
||||
protected abstract void insertDiscoFieldValues(
|
||||
Collection<DiscoExtensionFieldValueEntity> value);
|
||||
|
||||
@Upsert(entity = DiscoItemEntity.class)
|
||||
protected abstract void updateDiscoIdInDiscoItem(DiscoItemWithDiscoId item);
|
||||
|
||||
@Insert
|
||||
protected abstract long insert(DiscoEntity entity);
|
||||
|
||||
|
@ -73,7 +78,8 @@ public abstract class DiscoDao {
|
|||
public void set(
|
||||
final Account account, final Entity.DiscoItem parent, final Collection<Item> items) {
|
||||
final var entities =
|
||||
Collections2.transform(items, i -> DiscoItemWithParent.of(account.id, parent, i));
|
||||
Collections2.transform(
|
||||
items, i -> DiscoItemEntity.of(account.id, parent.address, i));
|
||||
insertDiscoItems(entities);
|
||||
deleteNonExistentDiscoItems(
|
||||
account.id, parent.address, Collections2.transform(items, Item::getJid));
|
||||
|
@ -106,8 +112,12 @@ public abstract class DiscoDao {
|
|||
@Nullable final String node,
|
||||
final long discoId) {
|
||||
if (entity instanceof Entity.DiscoItem) {
|
||||
updateDiscoIdInDiscoItem(
|
||||
DiscoItemWithDiscoId.of(account, (Entity.DiscoItem) entity, node, discoId));
|
||||
if (updateDiscoIdInDiscoItem(
|
||||
account, entity.address, Strings.nullToEmpty(node), discoId)
|
||||
> 0) {
|
||||
return;
|
||||
}
|
||||
insert(DiscoItemEntity.of(account, entity.address, node, discoId));
|
||||
} else if (entity instanceof Entity.Presence) {
|
||||
updateDiscoIdInPresence(
|
||||
account,
|
||||
|
@ -167,41 +177,4 @@ public abstract class DiscoDao {
|
|||
+ " disco_item.discoId=disco_feature.discoId WHERE accountId=:account AND"
|
||||
+ " address=:entity AND feature=:feature)")
|
||||
public abstract boolean hasFeature(final long account, final Jid entity, final String feature);
|
||||
|
||||
public static class DiscoItemWithParent {
|
||||
public long accountId;
|
||||
public @NonNull Jid address;
|
||||
public @NonNull String node;
|
||||
public @Nullable Jid parent;
|
||||
|
||||
public static DiscoItemWithParent of(
|
||||
final long account, Entity.DiscoItem parent, final Item item) {
|
||||
final var entity = new DiscoItemWithParent();
|
||||
entity.accountId = account;
|
||||
entity.address = item.getJid();
|
||||
entity.node = Strings.nullToEmpty(item.getNode());
|
||||
entity.parent = parent.address;
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DiscoItemWithDiscoId {
|
||||
public long accountId;
|
||||
public @NonNull Jid address;
|
||||
public @NonNull String node;
|
||||
public long discoId;
|
||||
|
||||
public static DiscoItemWithDiscoId of(
|
||||
final long account,
|
||||
final Entity.DiscoItem discoItem,
|
||||
@NonNull final String node,
|
||||
final long discoId) {
|
||||
final var entity = new DiscoItemWithDiscoId();
|
||||
entity.accountId = account;
|
||||
entity.address = discoItem.address;
|
||||
entity.node = node;
|
||||
entity.discoId = discoId;
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.room.Embedded;
|
|||
import androidx.room.Entity;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
import im.conversations.android.database.model.Connection;
|
||||
import im.conversations.android.database.model.Proxy;
|
||||
|
||||
|
@ -20,7 +21,7 @@ public class AccountEntity {
|
|||
@PrimaryKey(autoGenerate = true)
|
||||
public Long id;
|
||||
|
||||
@NonNull public String address;
|
||||
@NonNull public Jid address;
|
||||
public String resource;
|
||||
public byte[] randomSeed;
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package im.conversations.android.database.entity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.ForeignKey;
|
||||
import androidx.room.Index;
|
||||
import androidx.room.PrimaryKey;
|
||||
import com.google.common.base.Strings;
|
||||
import eu.siacs.conversations.xmpp.Jid;
|
||||
import im.conversations.android.xmpp.model.disco.items.Item;
|
||||
|
||||
@Entity(
|
||||
tableName = "disco_item",
|
||||
|
@ -24,7 +25,7 @@ import eu.siacs.conversations.xmpp.Jid;
|
|||
},
|
||||
indices = {
|
||||
@Index(
|
||||
value = {"accountId", "address", "node"},
|
||||
value = {"accountId", "address", "node", "parent"},
|
||||
unique = true),
|
||||
@Index(
|
||||
value = {"accountId", "parent"},
|
||||
|
@ -36,13 +37,33 @@ public class DiscoItemEntity {
|
|||
@PrimaryKey(autoGenerate = true)
|
||||
public Long id;
|
||||
|
||||
@NonNull Long accountId;
|
||||
@NonNull public Long accountId;
|
||||
|
||||
@NonNull Jid address;
|
||||
@NonNull public Jid address;
|
||||
|
||||
@NonNull public String node;
|
||||
|
||||
@Nullable public Jid parent;
|
||||
@NonNull public String parent;
|
||||
|
||||
public Long discoId;
|
||||
|
||||
public static DiscoItemEntity of(long accountId, final Jid parent, Item item) {
|
||||
final var entity = new DiscoItemEntity();
|
||||
entity.accountId = accountId;
|
||||
entity.address = item.getJid();
|
||||
entity.node = Strings.nullToEmpty(item.getNode());
|
||||
entity.parent = parent.toEscapedString();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static DiscoItemEntity of(
|
||||
long accountId, final Jid address, final String node, final long discoId) {
|
||||
final var entity = new DiscoItemEntity();
|
||||
entity.accountId = accountId;
|
||||
entity.address = address;
|
||||
entity.node = Strings.nullToEmpty(node);
|
||||
entity.parent = "";
|
||||
entity.discoId = discoId;
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,15 +55,53 @@ public class ConnectionPool {
|
|||
reconfigurationExecutor);
|
||||
}
|
||||
|
||||
public synchronized XmppConnection get(final Jid address) {
|
||||
return Iterables.find(this.connections, c -> address.equals(c.getAccount().address));
|
||||
public synchronized XmppConnection reconfigure(final Account account) {
|
||||
final Optional<XmppConnection> xmppConnectionOptional =
|
||||
Iterables.tryFind(this.connections, c -> c.getAccount().equals(account));
|
||||
if (xmppConnectionOptional.isPresent()) {
|
||||
return xmppConnectionOptional.get();
|
||||
}
|
||||
return setupXmppConnection(context, account);
|
||||
}
|
||||
|
||||
public synchronized XmppConnection get(final long id) {
|
||||
return Iterables.find(this.connections, c -> id == c.getAccount().id);
|
||||
public synchronized ListenableFuture<XmppConnection> get(final Jid address) {
|
||||
final var configured =
|
||||
Iterables.tryFind(this.connections, c -> address.equals(c.getAccount().address));
|
||||
if (configured.isPresent()) {
|
||||
return Futures.immediateFuture(configured.get());
|
||||
}
|
||||
return Futures.transform(
|
||||
ConversationsDatabase.getInstance(context).accountDao().getEnabledAccount(address),
|
||||
account -> {
|
||||
if (account == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"No enabled account with address %s",
|
||||
address.toEscapedString()));
|
||||
}
|
||||
return reconfigure(account);
|
||||
},
|
||||
reconfigurationExecutor);
|
||||
}
|
||||
|
||||
public synchronized boolean isEnabled(final long id) {
|
||||
public synchronized ListenableFuture<XmppConnection> get(final long id) {
|
||||
final var configured = Iterables.tryFind(this.connections, c -> id == c.getAccount().id);
|
||||
if (configured.isPresent()) {
|
||||
return Futures.immediateFuture(configured.get());
|
||||
}
|
||||
return Futures.transform(
|
||||
ConversationsDatabase.getInstance(context).accountDao().getEnabledAccount(id),
|
||||
account -> {
|
||||
if (account == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("No enabled account with id %d", id));
|
||||
}
|
||||
return reconfigure(account);
|
||||
},
|
||||
reconfigurationExecutor);
|
||||
}
|
||||
|
||||
private synchronized boolean isEnabled(final long id) {
|
||||
return Iterables.any(this.connections, c -> id == c.getAccount().id);
|
||||
}
|
||||
|
||||
|
@ -76,9 +114,7 @@ public class ConnectionPool {
|
|||
final Set<Account> removed = Sets.difference(current, accounts);
|
||||
final Set<Account> added = Sets.difference(accounts, current);
|
||||
for (final Account account : added) {
|
||||
final XmppConnection connection = this.instantiate(context, account);
|
||||
connection.setOnStatusChangedListener(this::onStatusChanged);
|
||||
reconnectAccount(connection);
|
||||
this.setupXmppConnection(context, account);
|
||||
}
|
||||
for (final Account account : removed) {
|
||||
final Optional<XmppConnection> connectionOptional =
|
||||
|
@ -324,9 +360,11 @@ public class ConnectionPool {
|
|||
}
|
||||
}
|
||||
|
||||
private XmppConnection instantiate(final Context context, final Account account) {
|
||||
private XmppConnection setupXmppConnection(final Context context, final Account account) {
|
||||
final XmppConnection xmppConnection = new XmppConnection(context, account);
|
||||
this.connections.add(xmppConnection);
|
||||
xmppConnection.setOnStatusChangedListener(this::onStatusChanged);
|
||||
reconnectAccount(xmppConnection);
|
||||
return xmppConnection;
|
||||
}
|
||||
|
||||
|
|
|
@ -1979,6 +1979,7 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
private void finalizeBind() {
|
||||
this.enableAdvancedStreamFeatures();
|
||||
this.bindConsumer.accept(this.connectionAddress);
|
||||
this.changeStatusToOnline();
|
||||
}
|
||||
|
@ -1989,10 +1990,6 @@ public class XmppConnection implements Runnable {
|
|||
&& !this.carbonsEnabled) {
|
||||
sendEnableCarbons();
|
||||
}
|
||||
// TODO discover commands
|
||||
/*if (getFeatures().commands()) {
|
||||
discoverCommands();
|
||||
}*/
|
||||
}
|
||||
|
||||
private void sendEnableCarbons() {
|
||||
|
|
Loading…
Reference in a new issue