diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt index da41d27a..121e61b9 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/database/ApplicationDao.kt @@ -188,12 +188,30 @@ interface ApplicationDao { @Transaction suspend fun insertPermissions2Raw(permissions: List): List? - suspend fun insertPermissions2(permissions: List): List? = insertPermissions2Raw(permissions) + @Query("SELECT `key` FROM application WHERE `key` IN (:keys)") + suspend fun getExistingApplicationKeys(keys: List): List + + /** + * Inserts permissions, skipping rows whose parent application no longer + * exists. `OnConflictStrategy.IGNORE` does not cover foreign-key failures, + * so a permission written after its application was deleted (e.g. a toggle + * racing an app delete/reset) would otherwise crash with + * `SQLITE_CONSTRAINT_FOREIGNKEY`. + */ + @Transaction + suspend fun insertPermissions2(permissions: List): List? { + if (permissions.isEmpty()) return emptyList() + val existingKeys = getExistingApplicationKeys(permissions.map { it.pkKey }.distinct()).toSet() + val valid = permissions.filter { it.pkKey in existingKeys } + if (valid.isEmpty()) return emptyList() + return insertPermissions2Raw(valid) + } @Insert(onConflict = OnConflictStrategy.REPLACE) @Transaction suspend fun insertPermissionsRaw(permissions: List): List? + @Transaction suspend fun insertPermissions(permissions: List): List? { permissions.forEach { if (it.kind != null) { @@ -212,7 +230,7 @@ interface ApplicationDao { deletePermissions(it.pkKey, it.type) } } - return insertPermissions2Raw(permissions) + return insertPermissions2(permissions) } @Transaction diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/database/CachingApplicationDao.kt b/app/src/main/java/com/greenart7c3/nostrsigner/database/CachingApplicationDao.kt index dda2e5ea..9ac5a5d0 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/database/CachingApplicationDao.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/database/CachingApplicationDao.kt @@ -308,6 +308,8 @@ class CachingApplicationDao( override suspend fun insertPermissions2Raw(permissions: List): List? = delegate.insertPermissions2Raw(permissions) + override suspend fun getExistingApplicationKeys(keys: List): List = delegate.getExistingApplicationKeys(keys) + override suspend fun insertPermissionsRaw(permissions: List): List? = delegate.insertPermissionsRaw(permissions) override suspend fun deleteRaw(entity: ApplicationEntity) = delegate.deleteRaw(entity)