[db] clean up RepositoryDao and add more tests

This commit is contained in:
Torsten Grote
2022-06-14 13:26:12 -03:00
parent 40d5c60d63
commit 79160b68ec
8 changed files with 489 additions and 231 deletions

View File

@@ -127,4 +127,19 @@ internal class AppDaoTest : AppTest() {
assertEquals(0, appDao.getNumberOfAppsInCategory("C"))
}
@Test
fun testGetNumberOfAppsInRepository() {
val repoId = repoDao.insertOrReplace(getRandomRepo())
assertEquals(0, appDao.getNumberOfAppsInRepository(repoId))
appDao.insert(repoId, packageName1, app1, locales)
assertEquals(1, appDao.getNumberOfAppsInRepository(repoId))
appDao.insert(repoId, packageName2, app2, locales)
assertEquals(2, appDao.getNumberOfAppsInRepository(repoId))
appDao.insert(repoId, packageName3, app3, locales)
assertEquals(3, appDao.getNumberOfAppsInRepository(repoId))
}
}

View File

@@ -0,0 +1,269 @@
package org.fdroid.database
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.fdroid.database.TestUtils.assertRepoEquals
import org.fdroid.database.TestUtils.getOrFail
import org.fdroid.test.TestAppUtils.getRandomMetadataV2
import org.fdroid.test.TestRepoUtils.getRandomRepo
import org.fdroid.test.TestUtils.getRandomString
import org.fdroid.test.TestUtils.orNull
import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.random.Random
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail
@RunWith(AndroidJUnit4::class)
internal class RepositoryDaoTest : DbTest() {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
@Test
fun testInsertInitialRepository() {
val repo = InitialRepository(
name = getRandomString(),
address = getRandomString(),
description = getRandomString(),
certificate = getRandomString(),
version = Random.nextLong(),
enabled = Random.nextBoolean(),
weight = Random.nextInt(),
)
val repoId = repoDao.insert(repo)
val actualRepo = repoDao.getRepository(repoId) ?: fail()
assertEquals(repo.name, actualRepo.getName(locales))
assertEquals(repo.address, actualRepo.address)
assertEquals(repo.description, actualRepo.getDescription(locales))
assertEquals(repo.certificate, actualRepo.certificate)
assertEquals(repo.version, actualRepo.version)
assertEquals(repo.enabled, actualRepo.enabled)
assertEquals(repo.weight, actualRepo.weight)
assertEquals(-1, actualRepo.timestamp)
assertEquals(emptyList(), actualRepo.mirrors)
assertEquals(emptyList(), actualRepo.userMirrors)
assertEquals(emptyList(), actualRepo.disabledMirrors)
assertEquals(emptyList(), actualRepo.getMirrors())
assertEquals(emptyList(), actualRepo.antiFeatures)
assertEquals(emptyList(), actualRepo.categories)
assertEquals(emptyList(), actualRepo.releaseChannels)
assertNull(actualRepo.formatVersion)
assertNull(actualRepo.icon)
assertNull(actualRepo.lastUpdated)
assertNull(actualRepo.webBaseUrl)
}
@Test
fun testInsertEmptyRepo() {
// insert empty repo
val address = getRandomString()
val username = getRandomString().orNull()
val password = getRandomString().orNull()
val repoId = repoDao.insertEmptyRepo(address, username, password)
// check that repo got inserted as expected
val actualRepo = repoDao.getRepository(repoId) ?: fail()
assertEquals(address, actualRepo.address)
assertEquals(username, actualRepo.username)
assertEquals(password, actualRepo.password)
assertEquals(-1, actualRepo.timestamp)
assertEquals(emptyList(), actualRepo.getMirrors())
assertEquals(emptyList(), actualRepo.antiFeatures)
assertEquals(emptyList(), actualRepo.categories)
assertEquals(emptyList(), actualRepo.releaseChannels)
assertNull(actualRepo.formatVersion)
assertNull(actualRepo.icon)
assertNull(actualRepo.lastUpdated)
assertNull(actualRepo.webBaseUrl)
}
@Test
fun insertAndDeleteTwoRepos() {
// insert first repo
val repo1 = getRandomRepo()
val repoId1 = repoDao.insertOrReplace(repo1)
// check that first repo got added and retrieved as expected
repoDao.getRepositories().let { repos ->
assertEquals(1, repos.size)
assertRepoEquals(repo1, repos[0])
}
val repositoryPreferences1 = repoDao.getRepositoryPreferences(repoId1)
assertEquals(repoId1, repositoryPreferences1?.repoId)
// insert second repo
val repo2 = getRandomRepo()
val repoId2 = repoDao.insertOrReplace(repo2)
// check that both repos got added and retrieved as expected
listOf(
repoDao.getRepositories().sortedBy { it.repoId },
repoDao.getLiveRepositories().getOrFail().sortedBy { it.repoId },
).forEach { repos ->
assertEquals(2, repos.size)
assertRepoEquals(repo1, repos[0])
assertRepoEquals(repo2, repos[1])
}
val repositoryPreferences2 = repoDao.getRepositoryPreferences(repoId2)
assertEquals(repoId2, repositoryPreferences2?.repoId)
// second repo has one weight point more than first repo
assertEquals(repositoryPreferences1?.weight?.plus(1), repositoryPreferences2?.weight)
// remove first repo and check that the database only returns one
repoDao.deleteRepository(repoId1)
listOf(
repoDao.getRepositories(),
repoDao.getLiveRepositories().getOrFail(),
).forEach { repos ->
assertEquals(1, repos.size)
assertRepoEquals(repo2, repos[0])
}
assertNull(repoDao.getRepositoryPreferences(repoId1))
// remove second repo and check that all associated data got removed as well
repoDao.deleteRepository(repoId2)
assertEquals(0, repoDao.getRepositories().size)
assertEquals(0, repoDao.countMirrors())
assertEquals(0, repoDao.countAntiFeatures())
assertEquals(0, repoDao.countCategories())
assertEquals(0, repoDao.countReleaseChannels())
assertNull(repoDao.getRepositoryPreferences(repoId2))
}
@Test
fun insertTwoReposAndClearAll() {
val repo1 = getRandomRepo()
val repo2 = getRandomRepo()
repoDao.insertOrReplace(repo1)
repoDao.insertOrReplace(repo2)
assertEquals(2, repoDao.getRepositories().size)
assertEquals(2, repoDao.getLiveRepositories().getOrFail().size)
repoDao.clearAll()
assertEquals(0, repoDao.getRepositories().size)
assertEquals(0, repoDao.getLiveRepositories().getOrFail().size)
}
@Test
fun testSetRepositoryEnabled() {
// repo is enabled by default
val repoId = repoDao.insertOrReplace(getRandomRepo())
assertTrue(repoDao.getRepository(repoId)?.enabled ?: fail())
// disabled repo is disabled
repoDao.setRepositoryEnabled(repoId, false)
assertFalse(repoDao.getRepository(repoId)?.enabled ?: fail())
// enabling again works
repoDao.setRepositoryEnabled(repoId, true)
assertTrue(repoDao.getRepository(repoId)?.enabled ?: fail())
}
@Test
fun testUpdateUserMirrors() {
// repo is enabled by default
val repoId = repoDao.insertOrReplace(getRandomRepo())
assertEquals(emptyList(), repoDao.getRepository(repoId)?.userMirrors)
// add user mirrors
val userMirrors = listOf(getRandomString(), getRandomString(), getRandomString())
repoDao.updateUserMirrors(repoId, userMirrors)
val repo = repoDao.getRepository(repoId) ?: fail()
assertEquals(userMirrors, repo.userMirrors)
// user mirrors are part of all mirrors
val userDownloadMirrors = userMirrors.map { org.fdroid.download.Mirror(it) }
assertTrue(repo.getMirrors().containsAll(userDownloadMirrors))
// remove user mirrors
repoDao.updateUserMirrors(repoId, emptyList())
assertEquals(emptyList(), repoDao.getRepository(repoId)?.userMirrors)
}
@Test
fun testUpdateUsernameAndPassword() {
// repo has no username or password initially
val repoId = repoDao.insertOrReplace(getRandomRepo())
repoDao.getRepository(repoId)?.let { repo ->
assertEquals(null, repo.username)
assertEquals(null, repo.password)
} ?: fail()
// add user name and password
val username = getRandomString().orNull()
val password = getRandomString().orNull()
repoDao.updateUsernameAndPassword(repoId, username, password)
repoDao.getRepository(repoId)?.let { repo ->
assertEquals(username, repo.username)
assertEquals(password, repo.password)
} ?: fail()
}
@Test
fun testUpdateDisabledMirrors() {
// repo has no username or password initially
val repoId = repoDao.insertOrReplace(getRandomRepo())
repoDao.getRepository(repoId)?.let { repo ->
assertEquals(null, repo.username)
assertEquals(null, repo.password)
} ?: fail()
// add user name and password
val username = getRandomString().orNull()
val password = getRandomString().orNull()
repoDao.updateUsernameAndPassword(repoId, username, password)
repoDao.getRepository(repoId)?.let { repo ->
assertEquals(username, repo.username)
assertEquals(password, repo.password)
} ?: fail()
}
@Test
fun clearingRepoRemovesAllAssociatedData() {
// insert one repo with one app with one version
val repoId = repoDao.insertOrReplace(getRandomRepo())
val repositoryPreferences = repoDao.getRepositoryPreferences(repoId)
val packageId = getRandomString()
val versionId = getRandomString()
appDao.insert(repoId, packageId, getRandomMetadataV2())
val packageVersion = getRandomPackageVersionV2()
versionDao.insert(repoId, packageId, versionId, packageVersion, Random.nextBoolean())
// data is there as expected
assertEquals(1, repoDao.getRepositories().size)
assertEquals(1, appDao.getAppMetadata().size)
assertEquals(1, versionDao.getAppVersions(repoId, packageId).size)
assertTrue(versionDao.getVersionedStrings(repoId, packageId).isNotEmpty())
// clearing the repo removes apps and versions
repoDao.clear(repoId)
assertEquals(1, repoDao.getRepositories().size)
assertEquals(0, appDao.countApps())
assertEquals(0, appDao.countLocalizedFiles())
assertEquals(0, appDao.countLocalizedFileLists())
assertEquals(0, versionDao.getAppVersions(repoId, packageId).size)
assertEquals(0, versionDao.getVersionedStrings(repoId, packageId).size)
// preferences are not touched by clearing
assertEquals(repositoryPreferences, repoDao.getRepositoryPreferences(repoId))
}
@Test
fun certGetsUpdated() {
val repoId = repoDao.insertOrReplace(getRandomRepo())
assertEquals(1, repoDao.getRepositories().size)
assertEquals(null, repoDao.getRepositories()[0].certificate)
val cert = getRandomString()
repoDao.updateRepository(repoId, cert)
assertEquals(1, repoDao.getRepositories().size)
assertEquals(cert, repoDao.getRepositories()[0].certificate)
}
}

View File

@@ -1,110 +0,0 @@
package org.fdroid.database
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.fdroid.database.TestUtils.assertRepoEquals
import org.fdroid.test.TestAppUtils.getRandomMetadataV2
import org.fdroid.test.TestRepoUtils.getRandomRepo
import org.fdroid.test.TestUtils.getRandomString
import org.fdroid.test.TestVersionUtils.getRandomPackageVersionV2
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.random.Random
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
internal class RepositoryTest : DbTest() {
@Test
fun insertAndDeleteTwoRepos() {
// insert first repo
val repo1 = getRandomRepo()
val repoId1 = repoDao.insertOrReplace(repo1)
// check that first repo got added and retrieved as expected
var repos = repoDao.getRepositories()
assertEquals(1, repos.size)
assertRepoEquals(repo1, repos[0])
val repositoryPreferences1 = repoDao.getRepositoryPreferences(repoId1)
assertEquals(repoId1, repositoryPreferences1?.repoId)
// insert second repo
val repo2 = getRandomRepo()
val repoId2 = repoDao.insertOrReplace(repo2)
// check that both repos got added and retrieved as expected
repos = repoDao.getRepositories().sortedBy { it.repoId }
assertEquals(2, repos.size)
assertRepoEquals(repo1, repos[0])
assertRepoEquals(repo2, repos[1])
val repositoryPreferences2 = repoDao.getRepositoryPreferences(repoId2)
assertEquals(repoId2, repositoryPreferences2?.repoId)
assertEquals(repositoryPreferences1?.weight?.plus(1), repositoryPreferences2?.weight)
// remove first repo and check that the database only returns one
repoDao.deleteRepository(repos[0].repository.repoId)
assertEquals(1, repoDao.getRepositories().size)
// remove second repo as well and check that all associated data got removed as well
repoDao.deleteRepository(repos[1].repository.repoId)
assertEquals(0, repoDao.getRepositories().size)
assertEquals(0, repoDao.getMirrors().size)
assertEquals(0, repoDao.getAntiFeatures().size)
assertEquals(0, repoDao.getCategories().size)
assertEquals(0, repoDao.getReleaseChannels().size)
assertNull(repoDao.getRepositoryPreferences(repoId1))
assertNull(repoDao.getRepositoryPreferences(repoId2))
}
@Test
fun insertTwoReposAndClearAll() {
val repo1 = getRandomRepo()
val repo2 = getRandomRepo()
repoDao.insertOrReplace(repo1)
repoDao.insertOrReplace(repo2)
assertEquals(2, repoDao.getRepositories().size)
repoDao.clearAll()
assertEquals(0, repoDao.getRepositories().size)
}
@Test
fun clearingRepoRemovesAllAssociatedData() {
val repoId = repoDao.insertOrReplace(getRandomRepo())
val repositoryPreferences = repoDao.getRepositoryPreferences(repoId)
val packageId = getRandomString()
val versionId = getRandomString()
appDao.insert(repoId, packageId, getRandomMetadataV2())
val packageVersion = getRandomPackageVersionV2()
versionDao.insert(repoId, packageId, versionId, packageVersion, Random.nextBoolean())
assertEquals(1, repoDao.getRepositories().size)
assertEquals(1, appDao.getAppMetadata().size)
assertEquals(1, versionDao.getAppVersions(repoId, packageId).size)
assertTrue(versionDao.getVersionedStrings(repoId, packageId).isNotEmpty())
repoDao.clear(repoId)
assertEquals(1, repoDao.getRepositories().size)
assertEquals(0, appDao.countApps())
assertEquals(0, appDao.countLocalizedFiles())
assertEquals(0, appDao.countLocalizedFileLists())
assertEquals(0, versionDao.getAppVersions(repoId, packageId).size)
assertEquals(0, versionDao.getVersionedStrings(repoId, packageId).size)
// preferences are not touched by clearing
assertEquals(repositoryPreferences, repoDao.getRepositoryPreferences(repoId))
}
@Test
fun certGetsUpdated() {
val repoId = repoDao.insertOrReplace(getRandomRepo())
assertEquals(1, repoDao.getRepositories().size)
assertEquals(null, repoDao.getRepositories()[0].certificate)
val cert = getRandomString()
repoDao.updateRepository(repoId, cert)
assertEquals(1, repoDao.getRepositories().size)
assertEquals(cert, repoDao.getRepositories()[0].certificate)
}
}

View File

@@ -11,10 +11,17 @@ import org.junit.Assert
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
internal object TestUtils {
fun assertTimestampRecent(timestamp: Long?) {
assertNotNull(timestamp)
assertTrue(System.currentTimeMillis() - timestamp < 2000)
}
fun assertRepoEquals(repoV2: RepoV2, repo: Repository) {
val repoId = repo.repoId
// mirrors

View File

@@ -10,6 +10,7 @@ import org.fdroid.CompatibilityChecker
import org.fdroid.database.DbTest
import org.fdroid.database.IndexFormatVersion.TWO
import org.fdroid.database.Repository
import org.fdroid.database.TestUtils.assertTimestampRecent
import org.fdroid.download.Downloader
import org.fdroid.download.DownloaderFactory
import org.fdroid.index.IndexUpdateResult
@@ -27,6 +28,7 @@ import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail
@@ -65,6 +67,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val updatedRepo = repoDao.getRepository(repoId) ?: fail()
assertEquals(TWO, updatedRepo.formatVersion)
assertEquals(CERTIFICATE, updatedRepo.certificate)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -79,6 +82,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.updateNewRepo(repo, FINGERPRINT).noError()
assertEquals(IndexUpdateResult.Processed, result)
assertDbEquals(repoId, TestDataMidV2.index)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -93,6 +97,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.updateNewRepo(repo, FINGERPRINT).noError()
assertEquals(IndexUpdateResult.Processed, result)
assertDbEquals(repoId, TestDataMaxV2.index)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -107,6 +112,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.update(repo).noError()
assertEquals(IndexUpdateResult.Processed, result)
assertDbEquals(repoId, TestDataMidV2.index)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -122,6 +128,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.update(repo).noError()
assertEquals(IndexUpdateResult.Processed, result)
assertDbEquals(repoId, TestDataMinV2.index)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -137,6 +144,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.update(repo).noError()
assertEquals(IndexUpdateResult.Processed, result)
assertDbEquals(repoId, TestDataMaxV2.index)
assertTimestampRecent(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test
@@ -152,6 +160,7 @@ internal class IndexV2UpdaterTest : DbTest() {
val result = indexUpdater.update(repo).noError()
assertEquals(IndexUpdateResult.Unchanged, result)
assertDbEquals(repoId, TestDataMinV2.index)
assertNull(repoDao.getRepository(repoId)?.lastUpdated)
}
@Test

View File

@@ -96,6 +96,8 @@ public interface AppDao {
public fun getInstalledAppListItems(packageManager: PackageManager): LiveData<List<AppListItem>>
public fun getNumberOfAppsInCategory(category: String): Int
public fun getNumberOfAppsInRepository(repoId: Long): Int
}
public enum class AppListSortOrder {
@@ -452,6 +454,9 @@ internal interface AppDaoInt : AppDao {
WHERE pref.enabled = 1 AND categories LIKE '%,' || :category || ',%'""")
override fun getNumberOfAppsInCategory(category: String): Int
@Query("SELECT COUNT(*) FROM AppMetadata WHERE repoId = :repoId")
override fun getNumberOfAppsInRepository(repoId: Long): Int
@Query("DELETE FROM AppMetadata WHERE repoId = :repoId AND packageId = :packageId")
fun deleteAppMetadata(repoId: Long, packageId: String)

View File

@@ -121,8 +121,7 @@ public data class Repository(
*/
@JvmOverloads
public fun getAllMirrors(includeUserMirrors: Boolean = true): List<org.fdroid.download.Mirror> {
// FIXME decide whether we need to add our own address here
return listOf(org.fdroid.download.Mirror(address)) + mirrors.map {
return mirrors.map {
it.toDownloadMirror()
} + if (includeUserMirrors) userMirrors.map {
org.fdroid.download.Mirror(it)

View File

@@ -21,30 +21,76 @@ import org.fdroid.index.v2.RepoV2
public interface RepositoryDao {
/**
* Inserts a new [InitialRepository] from a fixture.
*
* @return the [Repository.repoId] of the inserted repo.
*/
public fun insert(initialRepo: InitialRepository)
public fun insert(initialRepo: InitialRepository): Long
/**
* Removes all repos and their preferences.
* Inserts an empty [Repository] for an initial update.
*
* @return the [Repository.repoId] of the inserted repo.
*/
public fun clearAll()
public fun getRepository(repoId: Long): Repository?
public fun insertEmptyRepo(
address: String,
username: String? = null,
password: String? = null,
): Long
public fun deleteRepository(repoId: Long)
/**
* Returns the repository with the given [repoId] or null, if none was found with that ID.
*/
public fun getRepository(repoId: Long): Repository?
/**
* Returns a list of all [Repository]s in the database.
*/
public fun getRepositories(): List<Repository>
/**
* Same as [getRepositories], but does return a [LiveData].
*/
public fun getLiveRepositories(): LiveData<List<Repository>>
public fun countAppsPerRepository(repoId: Long): Int
public fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
public fun updateUserMirrors(repoId: Long, mirrors: List<String>)
public fun updateUsernameAndPassword(repoId: Long, username: String?, password: String?)
public fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
/**
* Returns a live data of all categories declared by all [Repository]s.
*/
public fun getLiveCategories(): LiveData<List<Category>>
/**
* Enables or disables the repository with the given [repoId].
* Data from disabled repositories is ignored in many queries.
*/
public fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
/**
* Updates the user-defined mirrors of the repository with the given [repoId].
* The existing mirrors get overwritten with the given [mirrors].
*/
public fun updateUserMirrors(repoId: Long, mirrors: List<String>)
/**
* Updates the user name and password (for basic authentication)
* of the repository with the given [repoId].
* The existing user name and password get overwritten with the given [username] and [password].
*/
public fun updateUsernameAndPassword(repoId: Long, username: String?, password: String?)
/**
* Updates the disabled mirrors of the repository with the given [repoId].
* The existing disabled mirrors get overwritten with the given [disabledMirrors].
*/
public fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
/**
* Removes a [Repository] with the given [repoId] with all associated data from the database.
*/
public fun deleteRepository(repoId: Long)
/**
* Removes all repos and their preferences.
*/
public fun clearAll()
}
@Dao
@@ -72,7 +118,7 @@ internal interface RepositoryDaoInt : RepositoryDao {
fun insert(repositoryPreferences: RepositoryPreferences)
@Transaction
override fun insert(initialRepo: InitialRepository) {
override fun insert(initialRepo: InitialRepository): Long {
val repo = CoreRepository(
name = mapOf("en-US" to initialRepo.name),
address = initialRepo.address,
@@ -92,6 +138,7 @@ internal interface RepositoryDaoInt : RepositoryDao {
enabled = initialRepo.enabled,
)
insert(repositoryPreferences)
return repoId
}
@Transaction
@@ -125,37 +172,38 @@ internal interface RepositoryDaoInt : RepositoryDao {
@Transaction
@VisibleForTesting
fun insertOrReplace(repository: RepoV2): Long {
val repoId = insertOrReplace(repository.toCoreRepository(version = 0))
insertRepositoryPreferences(repoId)
fun insertOrReplace(repository: RepoV2, version: Long = 0): Long {
val repoId = insertOrReplace(repository.toCoreRepository(version = version))
val currentMaxWeight = getMaxRepositoryWeight()
val repositoryPreferences = RepositoryPreferences(repoId, currentMaxWeight + 1)
insert(repositoryPreferences)
insertRepoTables(repoId, repository)
return repoId
}
private fun insertRepositoryPreferences(repoId: Long) {
val currentMaxWeight = getMaxRepositoryWeight()
val repositoryPreferences = RepositoryPreferences(repoId, currentMaxWeight + 1)
insert(repositoryPreferences)
}
/**
* Use when replacing an existing repo with a full index.
* This removes all existing index data associated with this repo from the database,
* but does not touch repository preferences.
* @throws IllegalStateException if no repo with the given [repoId] exists.
*/
@Transaction
fun clear(repoId: Long) {
val repo = getRepository(repoId) ?: error("repo with id $repoId does not exist")
// this clears all foreign key associated data since the repo gets replaced
insertOrReplace(repo.repository)
}
@Query("SELECT MAX(weight) FROM RepositoryPreferences")
fun getMaxRepositoryWeight(): Int
@Transaction
override fun clearAll() {
deleteAllCoreRepositories()
deleteAllRepositoryPreferences()
}
@Query("SELECT * FROM CoreRepository WHERE repoId = :repoId")
override fun getRepository(repoId: Long): Repository?
@Transaction
@Query("SELECT * FROM CoreRepository")
override fun getRepositories(): List<Repository>
@Transaction
@Query("SELECT * FROM CoreRepository")
override fun getLiveRepositories(): LiveData<List<Repository>>
@Query("SELECT * FROM RepositoryPreferences WHERE repoId = :repoId")
fun getRepositoryPreferences(repoId: Long): RepositoryPreferences?
@RewriteQueriesToDropUnusedColumns
@Query("""SELECT * FROM Category
JOIN RepositoryPreferences AS pref USING (repoId)
WHERE pref.enabled = 1 GROUP BY id HAVING MAX(pref.weight)""")
override fun getLiveCategories(): LiveData<List<Category>>
/**
* Updates an existing repo with new data from a full index update.
@@ -180,10 +228,25 @@ internal interface RepositoryDaoInt : RepositoryDao {
insertReleaseChannels(repository.releaseChannels.toRepoReleaseChannel(repoId))
}
@Transaction
@Query("SELECT * FROM CoreRepository WHERE repoId = :repoId")
override fun getRepository(repoId: Long): Repository?
@Update
fun updateRepository(repo: CoreRepository): Int
/**
* Updates the certificate for the [Repository] with the given [repoId].
* This should be used for V1 index updating where we only get the full cert
* after reading the entire index file.
* V2 index should use [update] instead as there the certificate is known
* before reading full index.
*/
@Query("UPDATE CoreRepository SET certificate = :certificate WHERE repoId = :repoId")
fun updateRepository(repoId: Long, certificate: String)
@Update
fun updateRepositoryPreferences(preferences: RepositoryPreferences)
/**
* Used to update an existing repository with a given [jsonObject] JSON diff.
*/
@Transaction
fun updateRepository(repoId: Long, version: Long, jsonObject: JsonObject) {
// get existing repo
@@ -237,15 +300,6 @@ internal interface RepositoryDaoInt : RepositoryDao {
)
}
@Update
fun updateRepository(repo: CoreRepository): Int
@Query("UPDATE CoreRepository SET certificate = :certificate WHERE repoId = :repoId")
fun updateRepository(repoId: Long, certificate: String)
@Update
fun updateRepositoryPreferences(preferences: RepositoryPreferences)
@Query("UPDATE RepositoryPreferences SET enabled = :enabled WHERE repoId = :repoId")
override fun setRepositoryEnabled(repoId: Long, enabled: Boolean)
@@ -260,73 +314,6 @@ internal interface RepositoryDaoInt : RepositoryDao {
WHERE repoId = :repoId""")
override fun updateDisabledMirrors(repoId: Long, disabledMirrors: List<String>)
@Transaction
@Query("SELECT * FROM CoreRepository")
override fun getRepositories(): List<Repository>
@Transaction
@Query("SELECT * FROM CoreRepository")
override fun getLiveRepositories(): LiveData<List<Repository>>
@VisibleForTesting
@Query("SELECT * FROM Mirror")
fun getMirrors(): List<Mirror>
@VisibleForTesting
@Query("DELETE FROM Mirror WHERE repoId = :repoId")
fun deleteMirrors(repoId: Long)
@VisibleForTesting
@Query("SELECT * FROM AntiFeature")
fun getAntiFeatures(): List<AntiFeature>
@Query("SELECT * FROM RepositoryPreferences WHERE repoId = :repoId")
fun getRepositoryPreferences(repoId: Long): RepositoryPreferences?
@Query("SELECT MAX(weight) FROM RepositoryPreferences")
fun getMaxRepositoryWeight(): Int
@VisibleForTesting
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId")
fun deleteAntiFeatures(repoId: Long)
@VisibleForTesting
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId AND id = :id")
fun deleteAntiFeature(repoId: Long, id: String)
@VisibleForTesting
@Query("SELECT * FROM Category")
fun getCategories(): List<Category>
@RewriteQueriesToDropUnusedColumns
@Query("""SELECT * FROM Category
JOIN RepositoryPreferences AS pref USING (repoId)
WHERE pref.enabled = 1 GROUP BY id HAVING MAX(pref.weight)""")
override fun getLiveCategories(): LiveData<List<Category>>
@Query("SELECT COUNT(*) FROM AppMetadata WHERE repoId = :repoId")
override fun countAppsPerRepository(repoId: Long): Int
@VisibleForTesting
@Query("DELETE FROM Category WHERE repoId = :repoId")
fun deleteCategories(repoId: Long)
@VisibleForTesting
@Query("DELETE FROM Category WHERE repoId = :repoId AND id = :id")
fun deleteCategory(repoId: Long, id: String)
@VisibleForTesting
@Query("SELECT * FROM ReleaseChannel")
fun getReleaseChannels(): List<ReleaseChannel>
@VisibleForTesting
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId")
fun deleteReleaseChannels(repoId: Long)
@VisibleForTesting
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId AND id = :id")
fun deleteReleaseChannel(repoId: Long, id: String)
@Transaction
override fun deleteRepository(repoId: Long) {
deleteCoreRepository(repoId)
@@ -338,13 +325,90 @@ internal interface RepositoryDaoInt : RepositoryDao {
@Query("DELETE FROM CoreRepository WHERE repoId = :repoId")
fun deleteCoreRepository(repoId: Long)
@Query("DELETE FROM CoreRepository")
fun deleteAllCoreRepositories()
@Query("DELETE FROM RepositoryPreferences WHERE repoId = :repoId")
fun deleteRepositoryPreferences(repoId: Long)
@Query("DELETE FROM CoreRepository")
fun deleteAllCoreRepositories()
@Query("DELETE FROM RepositoryPreferences")
fun deleteAllRepositoryPreferences()
/**
* Used for diffing.
*/
@Query("DELETE FROM Mirror WHERE repoId = :repoId")
fun deleteMirrors(repoId: Long)
/**
* Used for diffing.
*/
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId")
fun deleteAntiFeatures(repoId: Long)
/**
* Used for diffing.
*/
@Query("DELETE FROM AntiFeature WHERE repoId = :repoId AND id = :id")
fun deleteAntiFeature(repoId: Long, id: String)
/**
* Used for diffing.
*/
@Query("DELETE FROM Category WHERE repoId = :repoId")
fun deleteCategories(repoId: Long)
/**
* Used for diffing.
*/
@Query("DELETE FROM Category WHERE repoId = :repoId AND id = :id")
fun deleteCategory(repoId: Long, id: String)
/**
* Used for diffing.
*/
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId")
fun deleteReleaseChannels(repoId: Long)
/**
* Used for diffing.
*/
@Query("DELETE FROM ReleaseChannel WHERE repoId = :repoId AND id = :id")
fun deleteReleaseChannel(repoId: Long, id: String)
/**
* Use when replacing an existing repo with a full index.
* This removes all existing index data associated with this repo from the database,
* but does not touch repository preferences.
* @throws IllegalStateException if no repo with the given [repoId] exists.
*/
@Transaction
fun clear(repoId: Long) {
val repo = getRepository(repoId) ?: error("repo with id $repoId does not exist")
// this clears all foreign key associated data since the repo gets replaced
insertOrReplace(repo.repository)
}
@Transaction
override fun clearAll() {
deleteAllCoreRepositories()
deleteAllRepositoryPreferences()
}
@VisibleForTesting
@Query("SELECT COUNT(*) FROM Mirror")
fun countMirrors(): Int
@VisibleForTesting
@Query("SELECT COUNT(*) FROM AntiFeature")
fun countAntiFeatures(): Int
@VisibleForTesting
@Query("SELECT COUNT(*) FROM Category")
fun countCategories(): Int
@VisibleForTesting
@Query("SELECT COUNT(*) FROM ReleaseChannel")
fun countReleaseChannels(): Int
}