mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-25 16:17:58 +00:00
Initial commit: Pezkuwi Wallet Android
Complete rebrand of Nova Wallet for Pezkuwichain ecosystem. ## Features - Full Pezkuwichain support (HEZ & PEZ tokens) - Polkadot ecosystem compatibility - Staking, Governance, DeFi, NFTs - XCM cross-chain transfers - Hardware wallet support (Ledger, Polkadot Vault) - WalletConnect v2 - Push notifications ## Languages - English, Turkish, Kurmanci (Kurdish), Spanish, French, German, Russian, Japanese, Chinese, Korean, Portuguese, Vietnamese Based on Nova Wallet by Novasama Technologies GmbH © Dijital Kurdistan Tech Institute 2026
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import io.novafoundation.nova.core_db.model.AssetLocal
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AssetsDaoTest : DaoTest<AssetDao>(AppDatabase::assetDao) {
|
||||
|
||||
private val chainDao by dao<ChainDao>()
|
||||
private val metaAccountDao by dao<MetaAccountDao>()
|
||||
private val currencyDao by dao<CurrencyDao>()
|
||||
private val assetDao by dao<AssetDao>()
|
||||
|
||||
private var metaId: Long = 0
|
||||
|
||||
private val chainId = "0"
|
||||
private val testChain = createTestChain(chainId)
|
||||
private val asset = testChain.assets.first()
|
||||
private val assetId = asset.id
|
||||
|
||||
@Before
|
||||
fun setupDb() = runBlocking {
|
||||
metaId = metaAccountDao.insertMetaAccount(testMetaAccount())
|
||||
chainDao.addChain(testChain)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDeleteAssetAfterChainIsDeleted() = runBlocking {
|
||||
dao.insertAsset(AssetLocal.createEmpty(assetId = assetId, chainId = chainId, metaId))
|
||||
chainDao.removeChain(testChain)
|
||||
|
||||
val assets = dao.getSupportedAssets(metaId)
|
||||
|
||||
assert(assets.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingAssetsByMetaId() = runBlocking {
|
||||
currencyDao.insert(createCurrency(selected = true))
|
||||
|
||||
val assetWithToken = dao.getAssetWithToken(metaId, chainId, assetId)
|
||||
|
||||
assert(assetWithToken != null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingAssetsByMetaIdWithoutCurrency() = runBlocking {
|
||||
currencyDao.insert(createCurrency(selected = false))
|
||||
|
||||
val assetWithToken = dao.getAssetWithToken(metaId, chainId, assetId)
|
||||
|
||||
assert(assetWithToken == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingSyncedAssets() = runBlocking {
|
||||
assetDao.insertAsset(AssetLocal.createEmpty(assetId, chainId, metaId))
|
||||
currencyDao.insert(createCurrency(selected = true))
|
||||
|
||||
val assetWithToken = dao.getSyncedAssets(metaId)
|
||||
|
||||
assert(assetWithToken.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingSyncedAssetsWithoutCurrency() = runBlocking {
|
||||
assetDao.insertAsset(AssetLocal.createEmpty(assetId, chainId, metaId))
|
||||
currencyDao.insert(createCurrency(selected = false))
|
||||
|
||||
val assetsWithTokens = dao.getSyncedAssets(metaId)
|
||||
|
||||
assert(assetsWithTokens.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingSyncedAssetsWithoutAssetBalance() = runBlocking {
|
||||
currencyDao.insert(createCurrency(selected = false))
|
||||
|
||||
val assetsWithTokens = dao.getSyncedAssets(metaId)
|
||||
|
||||
assert(assetsWithTokens.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingSupportedAssets() = runBlocking {
|
||||
currencyDao.insert(createCurrency(selected = true))
|
||||
|
||||
val assetsWithTokens = dao.getSupportedAssets(metaId)
|
||||
|
||||
assert(assetsWithTokens.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRetrievingSupportedAssetsWithoutCurrency() = runBlocking {
|
||||
currencyDao.insert(createCurrency(selected = false))
|
||||
|
||||
val assetsWithTokens = dao.getSupportedAssets(metaId)
|
||||
|
||||
assert(assetsWithTokens.isEmpty())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.JoinedChainInfo
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ChainDaoTest : DaoTest<ChainDao>(AppDatabase::chainDao) {
|
||||
|
||||
@Test
|
||||
fun shouldInsertWholeChain() = runBlocking {
|
||||
val chainInfo = createTestChain("0x00")
|
||||
|
||||
dao.addChain(chainInfo)
|
||||
|
||||
val chainsFromDb = dao.getJoinChainInfo()
|
||||
|
||||
assertEquals(1, chainsFromDb.size)
|
||||
|
||||
val chainFromDb = chainsFromDb.first()
|
||||
|
||||
assertEquals(chainInfo.assets.size, chainFromDb.assets.size)
|
||||
assertEquals(chainInfo.nodes.size, chainFromDb.nodes.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDeleteChainWithCascade() = runBlocking {
|
||||
val chainInfo = createTestChain("0x00")
|
||||
|
||||
dao.addChain(chainInfo)
|
||||
dao.removeChain(chainInfo)
|
||||
|
||||
val assetsCursor = db.query("SELECT * FROM chain_assets", emptyArray())
|
||||
assertEquals(0, assetsCursor.count)
|
||||
|
||||
val nodesCursor = db.query("SELECT * FROM chain_nodes", emptyArray())
|
||||
assertEquals(0, nodesCursor.count)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldNotDeleteRuntimeCacheEntryAfterChainUpdate() = runBlocking {
|
||||
val chainInfo = createTestChain("0x00")
|
||||
|
||||
dao.addChain(chainInfo)
|
||||
dao.updateRemoteRuntimeVersionIfChainExists(chainInfo.chain.id, runtimeVersion = 1, transactionVersion = 1)
|
||||
|
||||
dao.updateChain(chainInfo)
|
||||
|
||||
val runtimeEntry = dao.runtimeInfo(chainInfo.chain.id)
|
||||
|
||||
assertNotNull(runtimeEntry)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldDeleteRemovedNestedFields() = runBlocking {
|
||||
val chainInfo = createTestChain("0x00", nodesCount = 3, assetsCount = 3)
|
||||
|
||||
dao.addChain(chainInfo)
|
||||
|
||||
dao.applyDiff(
|
||||
chainDiff = updatedDiff(chainInfo.chain),
|
||||
assetsDiff = CollectionDiffer.Diff(
|
||||
added = emptyList(),
|
||||
updated = emptyList(),
|
||||
removed = chainInfo.assets.takeLast(1),
|
||||
all = chainInfo.assets
|
||||
),
|
||||
nodesDiff = CollectionDiffer.Diff(
|
||||
added = emptyList(),
|
||||
updated = emptyList(),
|
||||
removed = chainInfo.nodes.takeLast(1),
|
||||
all = chainInfo.nodes
|
||||
),
|
||||
explorersDiff = emptyDiff(),
|
||||
externalApisDiff = emptyDiff(),
|
||||
nodeSelectionPreferencesDiff = emptyDiff()
|
||||
)
|
||||
|
||||
val chainFromDb2 = dao.getJoinChainInfo().first()
|
||||
|
||||
assertEquals(2, chainFromDb2.nodes.size)
|
||||
assertEquals(2, chainFromDb2.assets.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldUpdate() = runBlocking {
|
||||
val toBeRemoved = listOf(
|
||||
createTestChain("to be removed 1"),
|
||||
createTestChain("to be removed 2"),
|
||||
)
|
||||
|
||||
val stayTheSame = listOf(
|
||||
createTestChain("stay the same")
|
||||
)
|
||||
|
||||
val chainsInitial = listOf(createTestChain("to be changed")) + stayTheSame + toBeRemoved
|
||||
|
||||
dao.addChains(chainsInitial)
|
||||
|
||||
val added = listOf(createTestChain("to be added"))
|
||||
val updated = listOf(createTestChain("to be changed", "new name"))
|
||||
|
||||
val expectedResult = stayTheSame + added + updated
|
||||
|
||||
dao.applyDiff(
|
||||
chainDiff = CollectionDiffer.Diff(
|
||||
added = added.map(JoinedChainInfo::chain),
|
||||
updated = updated.map(JoinedChainInfo::chain),
|
||||
removed = toBeRemoved.map(JoinedChainInfo::chain),
|
||||
all = emptyList()
|
||||
),
|
||||
assetsDiff = emptyDiff(),
|
||||
nodesDiff = emptyDiff(),
|
||||
explorersDiff = emptyDiff(),
|
||||
externalApisDiff = emptyDiff(),
|
||||
nodeSelectionPreferencesDiff = emptyDiff()
|
||||
)
|
||||
|
||||
val chainsFromDb = dao.getJoinChainInfo()
|
||||
|
||||
assertEquals(expectedResult.size, chainsFromDb.size)
|
||||
expectedResult.forEach { expected ->
|
||||
val tryFind = chainsFromDb.firstOrNull { actual -> expected.chain.id == actual.chain.id && expected.chain.name == actual.chain.name }
|
||||
|
||||
assertNotNull("Did not find ${expected.chain.id} in result set", tryFind)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldUpdateRuntimeVersions() {
|
||||
runBlocking {
|
||||
val chainId = "0x00"
|
||||
|
||||
dao.addChain(createTestChain(chainId))
|
||||
|
||||
dao.updateRemoteRuntimeVersionIfChainExists(chainId, 1, transactionVersion = 1)
|
||||
|
||||
checkRuntimeVersions(remote = 1, synced = 0)
|
||||
|
||||
dao.updateSyncedRuntimeVersion(chainId, 1, localMigratorVersion = 1)
|
||||
|
||||
checkRuntimeVersions(remote = 1, synced = 1)
|
||||
|
||||
dao.updateRemoteRuntimeVersionIfChainExists(chainId, 2, transactionVersion = 1)
|
||||
|
||||
checkRuntimeVersions(remote = 2, synced = 1)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun checkRuntimeVersions(remote: Int, synced: Int) {
|
||||
val runtimeInfo = dao.runtimeInfo("0x00")
|
||||
|
||||
requireNotNull(runtimeInfo)
|
||||
|
||||
assertEquals(runtimeInfo.remoteVersion, remote)
|
||||
assertEquals(runtimeInfo.syncedVersion, synced)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import java.io.IOException
|
||||
|
||||
abstract class DaoTest<D : Any>(private val daoFetcher: (AppDatabase) -> D) {
|
||||
protected lateinit var dao: D
|
||||
protected lateinit var db: AppDatabase
|
||||
|
||||
@Before
|
||||
fun createDb() {
|
||||
val context = ApplicationProvider.getApplicationContext<Context>()
|
||||
|
||||
db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
|
||||
.build()
|
||||
|
||||
dao = daoFetcher(db)
|
||||
}
|
||||
|
||||
@After
|
||||
@Throws(IOException::class)
|
||||
fun closeDb() {
|
||||
db.close()
|
||||
}
|
||||
|
||||
protected inline fun <reified T> dao(): Lazy<T> = lazy {
|
||||
val method = db.javaClass.declaredMethods.first { it.returnType == T::class.java }
|
||||
|
||||
method.invoke(db) as T
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core.model.CryptoType
|
||||
import io.novafoundation.nova.core_db.model.CurrencyLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.AssetSourceLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExplorerLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExternalApiLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainNodeLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.JoinedChainInfo
|
||||
import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.ChainAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
|
||||
fun createTestChain(
|
||||
id: String,
|
||||
name: String = id,
|
||||
nodesCount: Int = 3,
|
||||
assetsCount: Int = 2,
|
||||
): JoinedChainInfo {
|
||||
val chain = chainOf(id, name)
|
||||
val nodes = with(chain) {
|
||||
(1..nodesCount).map {
|
||||
nodeOf("link${it}")
|
||||
}
|
||||
}
|
||||
val assets = with(chain) {
|
||||
(1..assetsCount).map {
|
||||
assetOf(assetId = it, symbol = it.toString())
|
||||
}
|
||||
}
|
||||
val explorers = emptyList<ChainExplorerLocal>()
|
||||
val externalApis = emptyList<ChainExternalApiLocal>()
|
||||
|
||||
return JoinedChainInfo(
|
||||
chain,
|
||||
NodeSelectionPreferencesLocal(chain.id, autoBalanceEnabled = true, selectedNodeUrl = null),
|
||||
nodes,
|
||||
assets,
|
||||
explorers,
|
||||
externalApis
|
||||
)
|
||||
}
|
||||
|
||||
fun chainOf(
|
||||
id: String,
|
||||
name: String = id,
|
||||
) = ChainLocal(
|
||||
id = id,
|
||||
parentId = null,
|
||||
name = name,
|
||||
icon = "Test",
|
||||
types = null,
|
||||
prefix = 0,
|
||||
legacyPrefix = null,
|
||||
isTestNet = false,
|
||||
isEthereumBased = false,
|
||||
hasCrowdloans = false,
|
||||
additional = "",
|
||||
governance = "governance",
|
||||
connectionState = ChainLocal.ConnectionStateLocal.FULL_SYNC,
|
||||
pushSupport = true,
|
||||
supportProxy = false,
|
||||
swap = "",
|
||||
hasSubstrateRuntime = true,
|
||||
nodeSelectionStrategy = ChainLocal.AutoBalanceStrategyLocal.ROUND_ROBIN,
|
||||
source = ChainLocal.Source.CUSTOM,
|
||||
customFee = "",
|
||||
multisigSupport = true
|
||||
)
|
||||
|
||||
fun ChainLocal.nodeOf(
|
||||
link: String,
|
||||
) = ChainNodeLocal(
|
||||
name = "Test",
|
||||
url = link,
|
||||
chainId = id,
|
||||
orderId = 0,
|
||||
source = ChainNodeLocal.Source.CUSTOM,
|
||||
)
|
||||
|
||||
fun ChainLocal.assetOf(
|
||||
assetId: Int,
|
||||
symbol: String,
|
||||
) = ChainAssetLocal(
|
||||
name = "Test",
|
||||
chainId = id,
|
||||
symbol = symbol,
|
||||
id = assetId,
|
||||
precision = 10,
|
||||
priceId = null,
|
||||
staking = "test",
|
||||
icon = "test",
|
||||
type = "test",
|
||||
buyProviders = "test",
|
||||
sellProviders = "test",
|
||||
typeExtras = null,
|
||||
enabled = true,
|
||||
source = AssetSourceLocal.DEFAULT
|
||||
)
|
||||
|
||||
suspend fun ChainDao.addChains(chains: List<JoinedChainInfo>) {
|
||||
applyDiff(
|
||||
chainDiff = addedDiff(chains.map(JoinedChainInfo::chain)),
|
||||
assetsDiff = addedDiff(chains.flatMap(JoinedChainInfo::assets)),
|
||||
nodesDiff = addedDiff(chains.flatMap(JoinedChainInfo::nodes)),
|
||||
explorersDiff = addedDiff(chains.flatMap(JoinedChainInfo::explorers)),
|
||||
externalApisDiff = addedDiff(chains.flatMap(JoinedChainInfo::externalApis)),
|
||||
nodeSelectionPreferencesDiff = emptyDiff()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun ChainDao.addChain(joinedChainInfo: JoinedChainInfo) = addChains(listOf(joinedChainInfo))
|
||||
|
||||
suspend fun ChainDao.removeChain(joinedChainInfo: JoinedChainInfo) {
|
||||
applyDiff(
|
||||
chainDiff = removedDiff(joinedChainInfo.chain),
|
||||
assetsDiff = removedDiff(joinedChainInfo.assets),
|
||||
nodesDiff = removedDiff(joinedChainInfo.nodes),
|
||||
explorersDiff = removedDiff(joinedChainInfo.explorers),
|
||||
externalApisDiff = removedDiff(joinedChainInfo.externalApis),
|
||||
nodeSelectionPreferencesDiff = emptyDiff()
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun ChainDao.updateChain(joinedChainInfo: JoinedChainInfo) {
|
||||
applyDiff(
|
||||
chainDiff = updatedDiff(joinedChainInfo.chain),
|
||||
assetsDiff = updatedDiff(joinedChainInfo.assets),
|
||||
nodesDiff = updatedDiff(joinedChainInfo.nodes),
|
||||
explorersDiff = updatedDiff(joinedChainInfo.explorers),
|
||||
externalApisDiff = updatedDiff(joinedChainInfo.externalApis),
|
||||
nodeSelectionPreferencesDiff = emptyDiff()
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> addedDiff(elements: List<T>) = CollectionDiffer.Diff(
|
||||
added = elements,
|
||||
updated = emptyList(),
|
||||
removed = emptyList(),
|
||||
all = elements
|
||||
)
|
||||
|
||||
fun <T> updatedDiff(elements: List<T>) = CollectionDiffer.Diff(
|
||||
added = emptyList(),
|
||||
updated = elements,
|
||||
removed = emptyList(),
|
||||
all = elements
|
||||
)
|
||||
|
||||
fun <T> updatedDiff(element: T) = updatedDiff(listOf(element))
|
||||
|
||||
fun <T> addedDiff(element: T) = addedDiff(listOf(element))
|
||||
|
||||
fun <T> removedDiff(element: T) = removedDiff(listOf(element))
|
||||
|
||||
fun <T> removedDiff(elements: List<T>) = CollectionDiffer.Diff(
|
||||
added = emptyList(),
|
||||
updated = emptyList(),
|
||||
removed = elements,
|
||||
all = elements
|
||||
)
|
||||
|
||||
fun <T> emptyDiff() = CollectionDiffer.Diff<T>(emptyList(), emptyList(), emptyList(), emptyList())
|
||||
|
||||
fun testMetaAccount(name: String = "Test") = MetaAccountLocal(
|
||||
substratePublicKey = byteArrayOf(),
|
||||
substrateCryptoType = CryptoType.SR25519,
|
||||
ethereumPublicKey = null,
|
||||
name = name,
|
||||
isSelected = false,
|
||||
substrateAccountId = byteArrayOf(),
|
||||
ethereumAddress = null,
|
||||
position = 0,
|
||||
type = MetaAccountLocal.Type.WATCH_ONLY,
|
||||
globallyUniqueId = "",
|
||||
parentMetaId = 1,
|
||||
status = MetaAccountLocal.Status.ACTIVE,
|
||||
typeExtras = null
|
||||
)
|
||||
|
||||
fun testChainAccount(
|
||||
metaId: Long,
|
||||
chainId: String,
|
||||
accountId: ByteArray = byteArrayOf()
|
||||
) = ChainAccountLocal(
|
||||
metaId = metaId,
|
||||
chainId = chainId,
|
||||
publicKey = byteArrayOf(),
|
||||
cryptoType = CryptoType.SR25519,
|
||||
accountId = accountId
|
||||
)
|
||||
|
||||
fun createCurrency(symbol: String = "$", selected: Boolean = true): CurrencyLocal {
|
||||
return CurrencyLocal(
|
||||
code = "USD",
|
||||
name = "Dollar",
|
||||
symbol = symbol,
|
||||
category = CurrencyLocal.Category.FIAT,
|
||||
popular = true,
|
||||
id = 0,
|
||||
coingeckoId = "usd",
|
||||
selected = selected
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
private const val CHAIN_ID = "1"
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MetaAccountDaoTest : DaoTest<MetaAccountDao>(AppDatabase::metaAccountDao) {
|
||||
|
||||
private val chainDao by dao<ChainDao>()
|
||||
|
||||
@Before
|
||||
fun insertChain() = runBlocking {
|
||||
chainDao.addChain(createTestChain(id = CHAIN_ID))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInsertMetaAccount() {
|
||||
runBlocking {
|
||||
dao.insertMetaAccount(testMetaAccount())
|
||||
dao.insertMetaAccount(testMetaAccount())
|
||||
|
||||
val accountsFromDb = dao.getMetaAccounts()
|
||||
|
||||
assertEquals(2, accountsFromDb.size)
|
||||
|
||||
val isIdAutoGenerated = accountsFromDb.withIndex().all { (index, account) ->
|
||||
account.id == index + 1L
|
||||
}
|
||||
|
||||
assertTrue("Id should be autogenerated", isIdAutoGenerated)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInsertAndRetrieveChainAccounts() {
|
||||
runBlocking {
|
||||
val metaId = dao.insertMetaAccount(testMetaAccount())
|
||||
|
||||
assertNotEquals(-1, metaId)
|
||||
|
||||
dao.insertChainAccount(testChainAccount(metaId, CHAIN_ID))
|
||||
|
||||
val joinedMetaAccountInfo = dao.getJoinedMetaAccountInfo(metaId)
|
||||
|
||||
assertEquals(1, joinedMetaAccountInfo.chainAccounts.size)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldReplaceChainAccounts() {
|
||||
runBlocking {
|
||||
val metaId = dao.insertMetaAccount(testMetaAccount())
|
||||
|
||||
val newAccountId = byteArrayOf(1)
|
||||
|
||||
dao.insertChainAccount(testChainAccount(metaId, CHAIN_ID, accountId = byteArrayOf(0)))
|
||||
dao.insertChainAccount(testChainAccount(metaId, CHAIN_ID, accountId = newAccountId))
|
||||
|
||||
val chainAccounts = dao.getJoinedMetaAccountInfo(metaId).chainAccounts
|
||||
|
||||
assertEquals(1, chainAccounts.size)
|
||||
assertArrayEquals(newAccountId, chainAccounts.single().accountId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TokenDaoTest : DaoTest<TokenDao>(AppDatabase::tokenDao) {
|
||||
|
||||
private val currencyDao by dao<CurrencyDao>()
|
||||
|
||||
private val tokenSymbol = "$"
|
||||
|
||||
@Test
|
||||
fun getTokenWhenCurrencySelected() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, true))
|
||||
|
||||
val tokenWithCurrency = dao.getTokenWithCurrency(tokenSymbol)
|
||||
|
||||
assert(tokenWithCurrency != null)
|
||||
assert(tokenWithCurrency?.token == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTokenWhenCurrencyNotSelected() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, false))
|
||||
|
||||
val token = dao.getTokenWithCurrency(tokenSymbol)
|
||||
|
||||
assert(token == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTokensWhenCurrencySelected() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, true))
|
||||
|
||||
val tokensWithCurrencies = dao.getTokensWithCurrency(listOf(tokenSymbol))
|
||||
|
||||
assert(tokensWithCurrencies.isNotEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getTokensWhenCurrencyNotSelected() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, false))
|
||||
|
||||
val tokensWithCurrencies = dao.getTokensWithCurrency(listOf(tokenSymbol))
|
||||
|
||||
assert(tokensWithCurrencies.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInsertTokenWithDefaultCurrency() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, true))
|
||||
|
||||
dao.insertTokenWithSelectedCurrency(tokenSymbol)
|
||||
val tokenWithCurrency = dao.getTokenWithCurrency(tokenSymbol)
|
||||
assert(tokenWithCurrency != null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldInsertTokenWithoutCurrency() = runBlocking {
|
||||
currencyDao.insert(createCurrency(tokenSymbol, false))
|
||||
|
||||
dao.insertTokenWithSelectedCurrency(tokenSymbol)
|
||||
val tokenWithCurrency = dao.getTokenWithCurrency(tokenSymbol)
|
||||
assert(tokenWithCurrency == null)
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.Room
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.room.testing.MigrationTestHelper
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Rule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
private const val DB_TEST_NAME = "test-db"
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
abstract class BaseMigrationTest {
|
||||
|
||||
@get:Rule
|
||||
val migrationHelper = MigrationTestHelper(
|
||||
InstrumentationRegistry.getInstrumentation(),
|
||||
AppDatabase::class.java.canonicalName,
|
||||
|
||||
FrameworkSQLiteOpenHelperFactory()
|
||||
)
|
||||
|
||||
protected fun runMigrationTest(
|
||||
from: Int,
|
||||
to: Int,
|
||||
vararg migrations: Migration,
|
||||
preMigrateBlock: (SupportSQLiteDatabase) -> Unit = {},
|
||||
postMigrateBlock: suspend (AppDatabase) -> Unit = {}
|
||||
) {
|
||||
runBlocking {
|
||||
val db = migrationHelper.createDatabase(DB_TEST_NAME, from)
|
||||
preMigrateBlock(db)
|
||||
|
||||
val validateDroppedTables = true
|
||||
migrationHelper.runMigrationsAndValidate(DB_TEST_NAME, to, validateDroppedTables, *migrations)
|
||||
|
||||
postMigrateBlock(getMigratedRoomDatabase(*migrations))
|
||||
}
|
||||
}
|
||||
|
||||
protected fun validateSchema(
|
||||
from: Int,
|
||||
to: Int,
|
||||
vararg migrations: Migration,
|
||||
) = runMigrationTest(from, to, *migrations)
|
||||
|
||||
private fun getMigratedRoomDatabase(vararg migrations: Migration): AppDatabase {
|
||||
val database: AppDatabase = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
|
||||
AppDatabase::class.java, DB_TEST_NAME)
|
||||
.addMigrations(*migrations)
|
||||
.build()
|
||||
|
||||
migrationHelper.closeWhenFinished(database)
|
||||
|
||||
return database
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import io.novafoundation.nova.core_db.converters.CryptoTypeConverters
|
||||
import io.novafoundation.nova.core_db.dao.assetOf
|
||||
import io.novafoundation.nova.core_db.dao.chainOf
|
||||
import io.novafoundation.nova.core_db.dao.testMetaAccount
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import java.math.BigInteger
|
||||
|
||||
private class OldAsset(
|
||||
val metaId: Long,
|
||||
val chainId: String,
|
||||
val tokenSymbol: String,
|
||||
val freeInPlanks: Int
|
||||
)
|
||||
|
||||
class BetterChainDiffingTest_8_9 : BaseMigrationTest() {
|
||||
|
||||
private val cryptoTypeConverters = CryptoTypeConverters()
|
||||
|
||||
var meta1Id: Long = -1
|
||||
var meta2Id: Long = -1
|
||||
|
||||
val chain1Id = "1"
|
||||
val chain2Id = "2"
|
||||
|
||||
private lateinit var assetsOld: List<OldAsset>
|
||||
|
||||
@Test
|
||||
fun validateMigration() = runMigrationTest(
|
||||
from = 8,
|
||||
to = 9,
|
||||
BetterChainDiffing_8_9,
|
||||
preMigrateBlock = ::preMigrate,
|
||||
postMigrateBlock = ::postMigrate
|
||||
)
|
||||
|
||||
private fun preMigrate(db: SupportSQLiteDatabase) {
|
||||
db.beginTransaction()
|
||||
|
||||
db.insertChain(chain1Id, assetSymbols = listOf("A", "B", "C"))
|
||||
db.insertChain(chain2Id, assetSymbols = listOf("C", "D", "E"))
|
||||
|
||||
meta1Id = db.insertMetaAccount(name = "1")
|
||||
meta2Id = db.insertMetaAccount(name = "2")
|
||||
|
||||
assetsOld = listOf(
|
||||
OldAsset(meta1Id, chain1Id, tokenSymbol = "A", freeInPlanks = 1),
|
||||
OldAsset(meta1Id, chain1Id, tokenSymbol = "B", freeInPlanks = 2),
|
||||
OldAsset(meta1Id, chain1Id, tokenSymbol = "C", freeInPlanks = 3),
|
||||
OldAsset(meta1Id, chain2Id, tokenSymbol = "C", freeInPlanks = 4),
|
||||
OldAsset(meta1Id, chain2Id, tokenSymbol = "D", freeInPlanks = 5),
|
||||
OldAsset(meta1Id, chain2Id, tokenSymbol = "E", freeInPlanks = 6),
|
||||
|
||||
OldAsset(meta2Id, chain1Id, tokenSymbol = "A", freeInPlanks = 11),
|
||||
OldAsset(meta2Id, chain1Id, tokenSymbol = "C", freeInPlanks = 13),
|
||||
)
|
||||
|
||||
assetsOld.forEach { db.insertAsset(it) }
|
||||
|
||||
db.setTransactionSuccessful()
|
||||
db.endTransaction()
|
||||
}
|
||||
|
||||
private suspend fun postMigrate(db: AppDatabase) {
|
||||
val assetsForMeta1 = db.assetDao().getSupportedAssets(meta1Id)
|
||||
|
||||
val symbolToAssetIdMapping = mapOf(
|
||||
(chain1Id to "A") to 0,
|
||||
(chain1Id to "B") to 1,
|
||||
(chain1Id to "C") to 2,
|
||||
(chain2Id to "C") to 0,
|
||||
(chain2Id to "D") to 1,
|
||||
(chain2Id to "E") to 2,
|
||||
)
|
||||
|
||||
assetsForMeta1.forEach {
|
||||
val actualChainId = it.asset!!.chainId
|
||||
val actualTokenSymbol = it.token!!.tokenSymbol
|
||||
|
||||
val assetIdExpected = symbolToAssetIdMapping[actualChainId to actualTokenSymbol]
|
||||
assertEquals(assetIdExpected, it.asset!!.assetId)
|
||||
|
||||
val expectedOldAsset = assetsOld.first { it.chainId == actualChainId && it.metaId == meta1Id && it.tokenSymbol == actualTokenSymbol }
|
||||
assertEquals(expectedOldAsset.freeInPlanks.toBigInteger(), it.asset!!.freeInPlanks)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SupportSQLiteDatabase.insertMetaAccount(
|
||||
name: String
|
||||
): Long {
|
||||
val metaAccount = testMetaAccount(name)
|
||||
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MetaAccountLocal.Table.Column.SUBSTRATE_PUBKEY, metaAccount.substratePublicKey)
|
||||
put(MetaAccountLocal.Table.Column.SUBSTRATE_ACCOUNT_ID, metaAccount.substrateAccountId)
|
||||
put(MetaAccountLocal.Table.Column.ETHEREUM_ADDRESS, metaAccount.ethereumAddress)
|
||||
put(MetaAccountLocal.Table.Column.ETHEREUM_PUBKEY, metaAccount.ethereumPublicKey)
|
||||
put(MetaAccountLocal.Table.Column.NAME, metaAccount.name)
|
||||
put(MetaAccountLocal.Table.Column.SUBSTRATE_CRYPTO_TYPE, cryptoTypeConverters.from(metaAccount.substrateCryptoType))
|
||||
put(MetaAccountLocal.Table.Column.IS_SELECTED, metaAccount.isSelected)
|
||||
put(MetaAccountLocal.Table.Column.POSITION, metaAccount.position)
|
||||
}
|
||||
|
||||
return insert(MetaAccountLocal.TABLE_NAME, 0, contentValues)
|
||||
}
|
||||
|
||||
private fun SupportSQLiteDatabase.insertChain(
|
||||
id: String,
|
||||
assetSymbols: List<String>
|
||||
) {
|
||||
val chain = chainOf(id)
|
||||
|
||||
val contentValues = ContentValues().apply {
|
||||
put("parentId", chain.parentId)
|
||||
put("name", chain.name)
|
||||
put("additional", chain.additional)
|
||||
put("id", chain.id)
|
||||
put("icon", chain.icon)
|
||||
// types
|
||||
putNull("url")
|
||||
putNull("overridesCommon")
|
||||
// externalApi
|
||||
putNull("staking_url")
|
||||
putNull("staking_type")
|
||||
putNull("history_type")
|
||||
putNull("history_url")
|
||||
putNull("crowdloans_url")
|
||||
putNull("crowdloans_type")
|
||||
|
||||
put("prefix", chain.prefix)
|
||||
put("isEthereumBased", chain.isEthereumBased)
|
||||
put("isTestNet", chain.isTestNet)
|
||||
put("hasCrowdloans", chain.hasCrowdloans)
|
||||
}
|
||||
|
||||
insert("chains", 0, contentValues)
|
||||
|
||||
val assets = assetSymbols.mapIndexed { index, symbol ->
|
||||
chain.assetOf(assetId = index, symbol)
|
||||
}
|
||||
|
||||
assets.forEach {
|
||||
val contentValues = ContentValues().apply {
|
||||
put("id", it.id)
|
||||
put("chainId", it.chainId)
|
||||
put("name", it.name)
|
||||
put("symbol", it.symbol)
|
||||
put("priceId", it.priceId)
|
||||
put("staking", it.staking)
|
||||
put("precision", it.precision)
|
||||
put("icon", it.icon)
|
||||
put("type", it.type)
|
||||
put("typeExtras", it.typeExtras)
|
||||
put("buyProviders", it.buyProviders)
|
||||
}
|
||||
|
||||
insert("chain_assets", 0, contentValues)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SupportSQLiteDatabase.insertAsset(oldAsset: OldAsset) {
|
||||
val tokenContentValues = ContentValues().apply {
|
||||
put("symbol", oldAsset.tokenSymbol)
|
||||
putNull("dollarRate")
|
||||
putNull("recentRateChange")
|
||||
}
|
||||
|
||||
insert("tokens", SQLiteDatabase.CONFLICT_REPLACE, tokenContentValues)
|
||||
|
||||
val assetContentValues = ContentValues().apply {
|
||||
put("tokenSymbol", oldAsset.tokenSymbol)
|
||||
put("chainId", oldAsset.chainId)
|
||||
put("metaId", oldAsset.metaId)
|
||||
|
||||
val amountZero = BigInteger.ZERO.toString()
|
||||
|
||||
put("freeInPlanks", oldAsset.freeInPlanks.toString())
|
||||
put("frozenInPlanks", amountZero)
|
||||
put("reservedInPlanks", amountZero)
|
||||
|
||||
put("bondedInPlanks", amountZero)
|
||||
put("redeemableInPlanks", amountZero)
|
||||
put("unbondingInPlanks", amountZero)
|
||||
}
|
||||
|
||||
insert("assets", 0, assetContentValues)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest />
|
||||
@@ -0,0 +1,341 @@
|
||||
package io.novafoundation.nova.core_db
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import io.novafoundation.nova.core_db.converters.AssetConverters
|
||||
import io.novafoundation.nova.core_db.converters.ChainConverters
|
||||
import io.novafoundation.nova.core_db.converters.CryptoTypeConverters
|
||||
import io.novafoundation.nova.core_db.converters.CurrencyConverters
|
||||
import io.novafoundation.nova.core_db.converters.ExternalApiConverters
|
||||
import io.novafoundation.nova.core_db.converters.ExternalBalanceTypeConverters
|
||||
import io.novafoundation.nova.core_db.converters.LongMathConverters
|
||||
import io.novafoundation.nova.core_db.converters.MetaAccountTypeConverters
|
||||
import io.novafoundation.nova.core_db.converters.NetworkTypeConverters
|
||||
import io.novafoundation.nova.core_db.converters.NftConverters
|
||||
import io.novafoundation.nova.core_db.converters.OperationConverters
|
||||
import io.novafoundation.nova.core_db.converters.ProxyAccountConverters
|
||||
import io.novafoundation.nova.core_db.dao.AccountDao
|
||||
import io.novafoundation.nova.core_db.dao.AccountStakingDao
|
||||
import io.novafoundation.nova.core_db.dao.AssetDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserHostSettingsDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserTabsDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainAssetDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainDao
|
||||
import io.novafoundation.nova.core_db.dao.CoinPriceDao
|
||||
import io.novafoundation.nova.core_db.dao.ContributionDao
|
||||
import io.novafoundation.nova.core_db.dao.CurrencyDao
|
||||
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
|
||||
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
|
||||
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.GiftsDao
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.HoldsDao
|
||||
import io.novafoundation.nova.core_db.dao.LockDao
|
||||
import io.novafoundation.nova.core_db.dao.MetaAccountDao
|
||||
import io.novafoundation.nova.core_db.dao.MultisigOperationsDao
|
||||
import io.novafoundation.nova.core_db.dao.NftDao
|
||||
import io.novafoundation.nova.core_db.dao.NodeDao
|
||||
import io.novafoundation.nova.core_db.dao.OperationDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingAddressDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingSitesDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingDashboardDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingRewardPeriodDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingTotalRewardDao
|
||||
import io.novafoundation.nova.core_db.dao.StorageDao
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.core_db.dao.TokenDao
|
||||
import io.novafoundation.nova.core_db.dao.WalletConnectSessionsDao
|
||||
import io.novafoundation.nova.core_db.migrations.AddAdditionalFieldToChains_12_13
|
||||
import io.novafoundation.nova.core_db.migrations.AddBalanceHolds_60_61
|
||||
import io.novafoundation.nova.core_db.migrations.AddBalanceModesToAssets_51_52
|
||||
import io.novafoundation.nova.core_db.migrations.AddBrowserHostSettings_34_35
|
||||
import io.novafoundation.nova.core_db.migrations.AddBrowserTabs_64_65
|
||||
import io.novafoundation.nova.core_db.migrations.AddBuyProviders_7_8
|
||||
import io.novafoundation.nova.core_db.migrations.AddChainColor_4_5
|
||||
import io.novafoundation.nova.core_db.migrations.AddChainForeignKeyForProxy_63_64
|
||||
import io.novafoundation.nova.core_db.migrations.AddConnectionStateToChains_53_54
|
||||
import io.novafoundation.nova.core_db.migrations.AddFieldsToContributions
|
||||
import io.novafoundation.nova.core_db.migrations.AddContributions_23_24
|
||||
import io.novafoundation.nova.core_db.migrations.AddCurrencies_18_19
|
||||
import io.novafoundation.nova.core_db.migrations.AddDAppAuthorizations_1_2
|
||||
import io.novafoundation.nova.core_db.migrations.AddEnabledColumnToChainAssets_30_31
|
||||
import io.novafoundation.nova.core_db.migrations.AddEventIdToOperation_47_48
|
||||
import io.novafoundation.nova.core_db.migrations.AddExternalBalances_45_46
|
||||
import io.novafoundation.nova.core_db.migrations.AddExtrinsicContentField_37_38
|
||||
import io.novafoundation.nova.core_db.migrations.AddFavoriteDAppsOrdering_65_66
|
||||
import io.novafoundation.nova.core_db.migrations.AddFavouriteDApps_9_10
|
||||
import io.novafoundation.nova.core_db.migrations.AddFungibleNfts_55_56
|
||||
import io.novafoundation.nova.core_db.migrations.AddGifts_71_72
|
||||
import io.novafoundation.nova.core_db.migrations.AddGloballyUniqueIdToMetaAccounts_58_59
|
||||
import io.novafoundation.nova.core_db.migrations.AddGovernanceDapps_25_26
|
||||
import io.novafoundation.nova.core_db.migrations.AddGovernanceExternalApiToChain_27_28
|
||||
import io.novafoundation.nova.core_db.migrations.AddGovernanceFlagToChains_24_25
|
||||
import io.novafoundation.nova.core_db.migrations.AddGovernanceNetworkToExternalApi_33_34
|
||||
import io.novafoundation.nova.core_db.migrations.AddLegacyAddressPrefix_66_67
|
||||
import io.novafoundation.nova.core_db.migrations.AddLocalMigratorVersionToChainRuntimes_57_58
|
||||
import io.novafoundation.nova.core_db.migrations.AddLocks_22_23
|
||||
import io.novafoundation.nova.core_db.migrations.AddMetaAccountType_14_15
|
||||
import io.novafoundation.nova.core_db.migrations.AddMultisigCalls_69_70
|
||||
import io.novafoundation.nova.core_db.migrations.AddMultisigSupportFlag_70_71
|
||||
import io.novafoundation.nova.core_db.migrations.AddNfts_5_6
|
||||
import io.novafoundation.nova.core_db.migrations.AddNodeSelectionStrategyField_38_39
|
||||
import io.novafoundation.nova.core_db.migrations.AddPoolIdToOperations_46_47
|
||||
import io.novafoundation.nova.core_db.migrations.AddProxyAccount_54_55
|
||||
import io.novafoundation.nova.core_db.migrations.AddRewardAccountToStakingDashboard_43_44
|
||||
import io.novafoundation.nova.core_db.migrations.AddRuntimeFlagToChains_36_37
|
||||
import io.novafoundation.nova.core_db.migrations.AddSellProviders_67_68
|
||||
import io.novafoundation.nova.core_db.migrations.AddSitePhishing_6_7
|
||||
import io.novafoundation.nova.core_db.migrations.AddSourceToLocalAsset_28_29
|
||||
import io.novafoundation.nova.core_db.migrations.AddStakingDashboardItems_41_42
|
||||
import io.novafoundation.nova.core_db.migrations.AddStakingTypeToTotalRewards_44_45
|
||||
import io.novafoundation.nova.core_db.migrations.AddSwapOption_48_49
|
||||
import io.novafoundation.nova.core_db.migrations.AddTransactionVersionToRuntime_50_51
|
||||
import io.novafoundation.nova.core_db.migrations.AddTransferApisTable_29_30
|
||||
import io.novafoundation.nova.core_db.migrations.AddTypeExtrasToMetaAccount_68_69
|
||||
import io.novafoundation.nova.core_db.migrations.AddVersioningToGovernanceDapps_32_33
|
||||
import io.novafoundation.nova.core_db.migrations.AddWalletConnectSessions_39_40
|
||||
import io.novafoundation.nova.core_db.migrations.AssetTypes_2_3
|
||||
import io.novafoundation.nova.core_db.migrations.BetterChainDiffing_8_9
|
||||
import io.novafoundation.nova.core_db.migrations.ChainNetworkManagement_59_60
|
||||
import io.novafoundation.nova.core_db.migrations.ChainNetworkManagement_61_62
|
||||
import io.novafoundation.nova.core_db.migrations.ChainPushSupport_56_57
|
||||
import io.novafoundation.nova.core_db.migrations.ChangeAsset_3_4
|
||||
import io.novafoundation.nova.core_db.migrations.ChangeChainNodes_20_21
|
||||
import io.novafoundation.nova.core_db.migrations.ChangeDAppAuthorization_10_11
|
||||
import io.novafoundation.nova.core_db.migrations.ChangeSessionTopicToParing_52_53
|
||||
import io.novafoundation.nova.core_db.migrations.ChangeTokens_19_20
|
||||
import io.novafoundation.nova.core_db.migrations.ExtractExternalApiToSeparateTable_35_36
|
||||
import io.novafoundation.nova.core_db.migrations.FixBrokenForeignKeys_31_32
|
||||
import io.novafoundation.nova.core_db.migrations.FixMigrationConflicts_13_14
|
||||
import io.novafoundation.nova.core_db.migrations.GovernanceFlagToEnum_26_27
|
||||
import io.novafoundation.nova.core_db.migrations.NullableSubstrateAccountId_21_22
|
||||
import io.novafoundation.nova.core_db.migrations.NullableSubstratePublicKey_15_16
|
||||
import io.novafoundation.nova.core_db.migrations.RefactorOperations_49_50
|
||||
import io.novafoundation.nova.core_db.migrations.RemoveChainForeignKeyFromChainAccount_11_12
|
||||
import io.novafoundation.nova.core_db.migrations.RemoveColorFromChains_17_18
|
||||
import io.novafoundation.nova.core_db.migrations.StakingRewardPeriods_42_43
|
||||
import io.novafoundation.nova.core_db.migrations.TinderGovBasket_62_63
|
||||
import io.novafoundation.nova.core_db.migrations.TransferFiatAmount_40_41
|
||||
import io.novafoundation.nova.core_db.migrations.WatchOnlyChainAccounts_16_17
|
||||
import io.novafoundation.nova.core_db.model.AccountLocal
|
||||
import io.novafoundation.nova.core_db.model.AccountStakingLocal
|
||||
import io.novafoundation.nova.core_db.model.AssetLocal
|
||||
import io.novafoundation.nova.core_db.model.BalanceHoldLocal
|
||||
import io.novafoundation.nova.core_db.model.BalanceLockLocal
|
||||
import io.novafoundation.nova.core_db.model.BrowserHostSettingsLocal
|
||||
import io.novafoundation.nova.core_db.model.BrowserTabLocal
|
||||
import io.novafoundation.nova.core_db.model.CoinPriceLocal
|
||||
import io.novafoundation.nova.core_db.model.ContributionLocal
|
||||
import io.novafoundation.nova.core_db.model.CurrencyLocal
|
||||
import io.novafoundation.nova.core_db.model.DappAuthorizationLocal
|
||||
import io.novafoundation.nova.core_db.model.ExternalBalanceLocal
|
||||
import io.novafoundation.nova.core_db.model.FavouriteDAppLocal
|
||||
import io.novafoundation.nova.core_db.model.GiftLocal
|
||||
import io.novafoundation.nova.core_db.model.GovernanceDAppLocal
|
||||
import io.novafoundation.nova.core_db.model.MultisigOperationCallLocal
|
||||
import io.novafoundation.nova.core_db.model.NftLocal
|
||||
import io.novafoundation.nova.core_db.model.NodeLocal
|
||||
import io.novafoundation.nova.core_db.model.PhishingAddressLocal
|
||||
import io.novafoundation.nova.core_db.model.PhishingSiteLocal
|
||||
import io.novafoundation.nova.core_db.model.StakingDashboardItemLocal
|
||||
import io.novafoundation.nova.core_db.model.StakingRewardPeriodLocal
|
||||
import io.novafoundation.nova.core_db.model.StorageEntryLocal
|
||||
import io.novafoundation.nova.core_db.model.TinderGovBasketItemLocal
|
||||
import io.novafoundation.nova.core_db.model.TinderGovVotingPowerLocal
|
||||
import io.novafoundation.nova.core_db.model.TokenLocal
|
||||
import io.novafoundation.nova.core_db.model.TotalRewardLocal
|
||||
import io.novafoundation.nova.core_db.model.WalletConnectPairingLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExplorerLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExternalApiLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainNodeLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainRuntimeInfoLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.ChainAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.ProxyAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.DirectRewardTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.ExtrinsicTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationBaseLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.PoolRewardTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.SwapTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.TransferTypeLocal
|
||||
|
||||
@Database(
|
||||
version = 73,
|
||||
entities = [
|
||||
AccountLocal::class,
|
||||
NodeLocal::class,
|
||||
AssetLocal::class,
|
||||
TokenLocal::class,
|
||||
PhishingAddressLocal::class,
|
||||
StorageEntryLocal::class,
|
||||
AccountStakingLocal::class,
|
||||
TotalRewardLocal::class,
|
||||
OperationBaseLocal::class,
|
||||
TransferTypeLocal::class,
|
||||
DirectRewardTypeLocal::class,
|
||||
PoolRewardTypeLocal::class,
|
||||
ExtrinsicTypeLocal::class,
|
||||
SwapTypeLocal::class,
|
||||
ChainLocal::class,
|
||||
ChainNodeLocal::class,
|
||||
ChainAssetLocal::class,
|
||||
ChainRuntimeInfoLocal::class,
|
||||
ChainExplorerLocal::class,
|
||||
ChainExternalApiLocal::class,
|
||||
MetaAccountLocal::class,
|
||||
ChainAccountLocal::class,
|
||||
DappAuthorizationLocal::class,
|
||||
NftLocal::class,
|
||||
PhishingSiteLocal::class,
|
||||
FavouriteDAppLocal::class,
|
||||
CurrencyLocal::class,
|
||||
BalanceLockLocal::class,
|
||||
ContributionLocal::class,
|
||||
GovernanceDAppLocal::class,
|
||||
BrowserHostSettingsLocal::class,
|
||||
WalletConnectPairingLocal::class,
|
||||
CoinPriceLocal::class,
|
||||
StakingDashboardItemLocal::class,
|
||||
StakingRewardPeriodLocal::class,
|
||||
ExternalBalanceLocal::class,
|
||||
ProxyAccountLocal::class,
|
||||
BalanceHoldLocal::class,
|
||||
NodeSelectionPreferencesLocal::class,
|
||||
TinderGovBasketItemLocal::class,
|
||||
TinderGovVotingPowerLocal::class,
|
||||
BrowserTabLocal::class,
|
||||
MultisigOperationCallLocal::class,
|
||||
GiftLocal::class
|
||||
],
|
||||
)
|
||||
@TypeConverters(
|
||||
LongMathConverters::class,
|
||||
NetworkTypeConverters::class,
|
||||
OperationConverters::class,
|
||||
CryptoTypeConverters::class,
|
||||
NftConverters::class,
|
||||
MetaAccountTypeConverters::class,
|
||||
CurrencyConverters::class,
|
||||
AssetConverters::class,
|
||||
ExternalApiConverters::class,
|
||||
ChainConverters::class,
|
||||
ExternalBalanceTypeConverters::class,
|
||||
ProxyAccountConverters::class,
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
|
||||
private var instance: AppDatabase? = null
|
||||
|
||||
@Synchronized
|
||||
fun get(
|
||||
context: Context
|
||||
): AppDatabase {
|
||||
if (instance == null) {
|
||||
instance = Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
AppDatabase::class.java,
|
||||
"app.db"
|
||||
)
|
||||
.addMigrations(AddDAppAuthorizations_1_2, AssetTypes_2_3, ChangeAsset_3_4)
|
||||
.addMigrations(AddChainColor_4_5, AddNfts_5_6, AddSitePhishing_6_7, AddBuyProviders_7_8, BetterChainDiffing_8_9)
|
||||
.addMigrations(AddFavouriteDApps_9_10, ChangeDAppAuthorization_10_11, RemoveChainForeignKeyFromChainAccount_11_12)
|
||||
.addMigrations(AddAdditionalFieldToChains_12_13, FixMigrationConflicts_13_14, AddMetaAccountType_14_15)
|
||||
.addMigrations(NullableSubstratePublicKey_15_16, WatchOnlyChainAccounts_16_17, RemoveColorFromChains_17_18)
|
||||
.addMigrations(AddCurrencies_18_19, ChangeTokens_19_20, ChangeChainNodes_20_21)
|
||||
.addMigrations(NullableSubstrateAccountId_21_22, AddLocks_22_23, AddContributions_23_24)
|
||||
.addMigrations(AddGovernanceFlagToChains_24_25, AddGovernanceDapps_25_26, GovernanceFlagToEnum_26_27)
|
||||
.addMigrations(AddGovernanceExternalApiToChain_27_28)
|
||||
.addMigrations(AddSourceToLocalAsset_28_29, AddTransferApisTable_29_30, AddEnabledColumnToChainAssets_30_31)
|
||||
.addMigrations(FixBrokenForeignKeys_31_32, AddVersioningToGovernanceDapps_32_33)
|
||||
.addMigrations(AddGovernanceNetworkToExternalApi_33_34, AddBrowserHostSettings_34_35)
|
||||
.addMigrations(ExtractExternalApiToSeparateTable_35_36, AddRuntimeFlagToChains_36_37)
|
||||
.addMigrations(AddExtrinsicContentField_37_38, AddNodeSelectionStrategyField_38_39)
|
||||
.addMigrations(AddWalletConnectSessions_39_40, TransferFiatAmount_40_41)
|
||||
.addMigrations(AddStakingDashboardItems_41_42, StakingRewardPeriods_42_43)
|
||||
.addMigrations(AddRewardAccountToStakingDashboard_43_44, AddStakingTypeToTotalRewards_44_45, AddExternalBalances_45_46)
|
||||
.addMigrations(AddPoolIdToOperations_46_47, AddEventIdToOperation_47_48, AddSwapOption_48_49)
|
||||
.addMigrations(RefactorOperations_49_50, AddTransactionVersionToRuntime_50_51, AddBalanceModesToAssets_51_52)
|
||||
.addMigrations(ChangeSessionTopicToParing_52_53, AddConnectionStateToChains_53_54, AddProxyAccount_54_55)
|
||||
.addMigrations(AddFungibleNfts_55_56, ChainPushSupport_56_57)
|
||||
.addMigrations(AddLocalMigratorVersionToChainRuntimes_57_58, AddGloballyUniqueIdToMetaAccounts_58_59)
|
||||
.addMigrations(ChainNetworkManagement_59_60, AddBalanceHolds_60_61, ChainNetworkManagement_61_62)
|
||||
.addMigrations(TinderGovBasket_62_63, AddChainForeignKeyForProxy_63_64, AddBrowserTabs_64_65)
|
||||
.addMigrations(AddFavoriteDAppsOrdering_65_66, AddLegacyAddressPrefix_66_67, AddSellProviders_67_68)
|
||||
.addMigrations(AddTypeExtrasToMetaAccount_68_69, AddMultisigCalls_69_70, AddMultisigSupportFlag_70_71)
|
||||
.addMigrations(AddGifts_71_72, AddFieldsToContributions)
|
||||
.build()
|
||||
}
|
||||
return instance!!
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun nodeDao(): NodeDao
|
||||
|
||||
abstract fun userDao(): AccountDao
|
||||
|
||||
abstract fun assetDao(): AssetDao
|
||||
|
||||
abstract fun operationDao(): OperationDao
|
||||
|
||||
abstract fun phishingAddressesDao(): PhishingAddressDao
|
||||
|
||||
abstract fun storageDao(): StorageDao
|
||||
|
||||
abstract fun tokenDao(): TokenDao
|
||||
|
||||
abstract fun accountStakingDao(): AccountStakingDao
|
||||
|
||||
abstract fun stakingTotalRewardDao(): StakingTotalRewardDao
|
||||
|
||||
abstract fun chainDao(): ChainDao
|
||||
|
||||
abstract fun chainAssetDao(): ChainAssetDao
|
||||
|
||||
abstract fun metaAccountDao(): MetaAccountDao
|
||||
|
||||
abstract fun dAppAuthorizationDao(): DappAuthorizationDao
|
||||
|
||||
abstract fun nftDao(): NftDao
|
||||
|
||||
abstract fun phishingSitesDao(): PhishingSitesDao
|
||||
|
||||
abstract fun favouriteDAppsDao(): FavouriteDAppsDao
|
||||
|
||||
abstract fun currencyDao(): CurrencyDao
|
||||
|
||||
abstract fun lockDao(): LockDao
|
||||
|
||||
abstract fun contributionDao(): ContributionDao
|
||||
|
||||
abstract fun governanceDAppsDao(): GovernanceDAppsDao
|
||||
|
||||
abstract fun browserHostSettingsDao(): BrowserHostSettingsDao
|
||||
|
||||
abstract fun walletConnectSessionsDao(): WalletConnectSessionsDao
|
||||
|
||||
abstract fun stakingDashboardDao(): StakingDashboardDao
|
||||
|
||||
abstract fun coinPriceDao(): CoinPriceDao
|
||||
|
||||
abstract fun stakingRewardPeriodDao(): StakingRewardPeriodDao
|
||||
|
||||
abstract fun externalBalanceDao(): ExternalBalanceDao
|
||||
|
||||
abstract fun holdsDao(): HoldsDao
|
||||
|
||||
abstract fun tinderGovDao(): TinderGovDao
|
||||
|
||||
abstract fun browserTabsDao(): BrowserTabsDao
|
||||
|
||||
abstract fun multisigOperationsDao(): MultisigOperationsDao
|
||||
|
||||
abstract fun giftsDao(): GiftsDao
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.AssetLocal.EDCountingModeLocal
|
||||
import io.novafoundation.nova.core_db.model.AssetLocal.TransferableModeLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.AssetSourceLocal
|
||||
|
||||
class AssetConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromCategory(type: AssetSourceLocal): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toCategory(name: String): AssetSourceLocal {
|
||||
return enumValueOf(name)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromTransferableMode(mode: TransferableModeLocal): Int {
|
||||
return mode.ordinal
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toTransferableMode(index: Int): TransferableModeLocal {
|
||||
return TransferableModeLocal.values()[index]
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromEdCountingMode(mode: EDCountingModeLocal): Int {
|
||||
return mode.ordinal
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toEdCountingMode(index: Int): EDCountingModeLocal {
|
||||
return EDCountingModeLocal.values()[index]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.common.utils.enumValueOfOrNull
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal.ConnectionStateLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal.AutoBalanceStrategyLocal
|
||||
|
||||
class ChainConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromNodeStrategy(strategy: AutoBalanceStrategyLocal): String = strategy.name
|
||||
|
||||
@TypeConverter
|
||||
fun toNodeStrategy(name: String): AutoBalanceStrategyLocal {
|
||||
return enumValueOfOrNull<AutoBalanceStrategyLocal>(name) ?: AutoBalanceStrategyLocal.UNKNOWN
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromConnection(connectionState: ConnectionStateLocal): String = connectionState.name
|
||||
|
||||
@TypeConverter
|
||||
fun toConnection(name: String): ConnectionStateLocal {
|
||||
return enumValueOfOrNull<ConnectionStateLocal>(name) ?: ConnectionStateLocal.LIGHT_SYNC
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core.model.CryptoType
|
||||
|
||||
class CryptoTypeConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun from(cryptoType: CryptoType?): String? = cryptoType?.name
|
||||
|
||||
@TypeConverter
|
||||
fun to(name: String?): CryptoType? = name?.let { enumValueOf<CryptoType>(it) }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.CurrencyLocal
|
||||
|
||||
class CurrencyConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromCategory(type: CurrencyLocal.Category): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toCategory(name: String): CurrencyLocal.Category {
|
||||
return enumValueOf(name)
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.common.utils.enumValueOfOrNull
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExternalApiLocal.SourceType
|
||||
|
||||
class ExternalApiConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromApiType(apiType: SourceType): String {
|
||||
return apiType.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toApiType(raw: String): SourceType {
|
||||
return enumValueOfOrNull<SourceType>(raw) ?: SourceType.UNKNOWN
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.ExternalBalanceLocal
|
||||
|
||||
class ExternalBalanceTypeConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromType(type: ExternalBalanceLocal.Type): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toType(name: String): ExternalBalanceLocal.Type {
|
||||
return ExternalBalanceLocal.Type.valueOf(name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
class LongMathConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromBigDecimal(balance: BigDecimal?): String? {
|
||||
return balance?.toString()
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toBigDecimal(balance: String?): BigDecimal? {
|
||||
return balance?.let { BigDecimal(it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromBigInteger(balance: BigInteger?): String? {
|
||||
return balance?.toString()
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toBigInteger(balance: String?): BigInteger? {
|
||||
return balance?.let {
|
||||
// When using aggregates like SUM in SQL queries, SQLite might return the result in a scientific notation especially if aggregation is done
|
||||
// BigInteger, which is stored as a string and SQLite casts it to REAL which causing the scientific notation on big numbers
|
||||
// This can be avoided by adjusting the query but we keep the fallback to BigDecimal parsing here anyways to avoid unpleasant crashes
|
||||
// It doesn't bring much impact since try-catch doesn't have an overhead unless the exception is thrown
|
||||
try {
|
||||
BigInteger(it)
|
||||
} catch (e: NumberFormatException) {
|
||||
BigDecimal(it).toBigInteger()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
|
||||
class MetaAccountTypeConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromEnum(type: MetaAccountLocal.Type): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toEnum(name: String): MetaAccountLocal.Type {
|
||||
return MetaAccountLocal.Type.valueOf(name)
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core.model.Node
|
||||
|
||||
class NetworkTypeConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromNetworkType(networkType: Node.NetworkType): Int {
|
||||
return networkType.ordinal
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toNetworkType(ordinal: Int): Node.NetworkType {
|
||||
return Node.NetworkType.values()[ordinal]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.NftLocal
|
||||
|
||||
class NftConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromNftType(type: NftLocal.Type): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toNftType(name: String): NftLocal.Type {
|
||||
return enumValueOf(name)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromNftIssuanceType(type: NftLocal.IssuanceType): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toNftIssuanceType(name: String): NftLocal.IssuanceType {
|
||||
return enumValueOf(name)
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.operation.ExtrinsicTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationBaseLocal
|
||||
|
||||
class OperationConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromOperationSource(source: OperationBaseLocal.Source) = source.ordinal
|
||||
|
||||
@TypeConverter
|
||||
fun toOperationSource(ordinal: Int) = OperationBaseLocal.Source.values()[ordinal]
|
||||
|
||||
@TypeConverter
|
||||
fun fromOperationStatus(status: OperationBaseLocal.Status) = status.ordinal
|
||||
|
||||
@TypeConverter
|
||||
fun toOperationStatus(ordinal: Int) = OperationBaseLocal.Status.values()[ordinal]
|
||||
|
||||
@TypeConverter
|
||||
fun fromExtrinsicContentType(type: ExtrinsicTypeLocal.ContentType) = type.name
|
||||
|
||||
@TypeConverter
|
||||
fun toExtrinsicContentType(name: String): ExtrinsicTypeLocal.ContentType = enumValueOf(name)
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.novafoundation.nova.core_db.converters
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
|
||||
class ProxyAccountConverters {
|
||||
@TypeConverter
|
||||
fun fromStatusType(type: MetaAccountLocal.Status): String {
|
||||
return type.name
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toStatusType(name: String): MetaAccountLocal.Status {
|
||||
return MetaAccountLocal.Status.valueOf(name)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.core.model.Node
|
||||
import io.novafoundation.nova.core_db.model.AccountLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class AccountDao {
|
||||
|
||||
@Query("select * from users order by networkType, position")
|
||||
abstract fun accountsFlow(): Flow<List<AccountLocal>>
|
||||
|
||||
@Query("select * from users order by networkType, position")
|
||||
abstract suspend fun getAccounts(): List<AccountLocal>
|
||||
|
||||
@Query("select * from users where address = :address")
|
||||
abstract suspend fun getAccount(address: String): AccountLocal?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
abstract suspend fun insert(account: AccountLocal): Long
|
||||
|
||||
@Query("DELETE FROM users where address = :address")
|
||||
abstract suspend fun remove(address: String)
|
||||
|
||||
@Update
|
||||
abstract suspend fun updateAccount(account: AccountLocal)
|
||||
|
||||
@Update
|
||||
abstract suspend fun updateAccounts(accounts: List<AccountLocal>)
|
||||
|
||||
@Query("SELECT COALESCE(MAX(position), 0) + 1 from users")
|
||||
abstract suspend fun getNextPosition(): Int
|
||||
|
||||
@Query("select * from users where networkType = :networkType")
|
||||
abstract suspend fun getAccountsByNetworkType(networkType: Int): List<AccountLocal>
|
||||
|
||||
@Query("select * from users where (address LIKE '%' || :query || '%') AND networkType = :networkType")
|
||||
abstract suspend fun getAccounts(query: String, networkType: Node.NetworkType): List<AccountLocal>
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM users WHERE address = :accountAddress)")
|
||||
abstract suspend fun accountExists(accountAddress: String): Boolean
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.AccountStakingLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
|
||||
private const val SELECT_QUERY = """
|
||||
SELECT * FROM account_staking_accesses
|
||||
WHERE accountId = :accountId AND chainId = :chainId AND chainAssetId = :chainAssetId
|
||||
"""
|
||||
|
||||
@Dao
|
||||
abstract class AccountStakingDao {
|
||||
|
||||
@Query(SELECT_QUERY)
|
||||
abstract suspend fun get(chainId: String, chainAssetId: Int, accountId: ByteArray): AccountStakingLocal
|
||||
|
||||
@Query(SELECT_QUERY)
|
||||
protected abstract fun observeInternal(chainId: String, chainAssetId: Int, accountId: ByteArray): Flow<AccountStakingLocal?>
|
||||
|
||||
fun observeDistinct(chainId: String, chainAssetId: Int, accountId: ByteArray): Flow<AccountStakingLocal> {
|
||||
return observeInternal(chainId, chainAssetId, accountId)
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(accountStaking: AccountStakingLocal)
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.common.utils.flowOfAll
|
||||
import io.novafoundation.nova.common.utils.mapToSet
|
||||
import io.novafoundation.nova.core_db.model.AssetAndChainId
|
||||
import io.novafoundation.nova.core_db.model.AssetLocal
|
||||
import io.novafoundation.nova.core_db.model.AssetWithToken
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
private const val RETRIEVE_ASSET_SQL_META_ID = """
|
||||
SELECT *, ca.chainId as ca_chainId, ca.id as ca_assetId FROM chain_assets AS ca
|
||||
LEFT JOIN assets AS a ON a.assetId = ca.id AND a.chainId = ca.chainId AND a.metaId = :metaId
|
||||
INNER JOIN currencies as currency ON currency.selected = 1
|
||||
LEFT JOIN tokens AS t ON ca.symbol = t.tokenSymbol AND currency.id = t.currencyId
|
||||
WHERE ca.chainId = :chainId AND ca.id = :assetId
|
||||
"""
|
||||
|
||||
private const val RETRIEVE_SYNCED_ACCOUNT_ASSETS_QUERY = """
|
||||
SELECT *, ca.chainId as ca_chainId, ca.id as ca_assetId FROM assets AS a
|
||||
INNER JOIN chain_assets AS ca ON a.assetId = ca.id AND a.chainId = ca.chainId
|
||||
INNER JOIN currencies as currency ON currency.selected = 1
|
||||
LEFT JOIN tokens AS t ON ca.symbol = t.tokenSymbol AND currency.id = t.currencyId
|
||||
WHERE a.metaId = :metaId
|
||||
"""
|
||||
|
||||
private const val RETRIEVE_SUPPORTED_ACCOUNT_ASSETS_QUERY = """
|
||||
SELECT *, ca.chainId as ca_chainId, ca.id as ca_assetId FROM chain_assets AS ca
|
||||
LEFT JOIN assets AS a ON a.assetId = ca.id AND a.chainId = ca.chainId AND a.metaId = :metaId
|
||||
INNER JOIN currencies as currency ON currency.selected = 1
|
||||
LEFT JOIN tokens AS t ON ca.symbol = t.tokenSymbol AND currency.id = t.currencyId
|
||||
"""
|
||||
|
||||
private const val RETRIEVE_ASSETS_SQL_META_ID = """
|
||||
SELECT *, ca.chainId as ca_chainId, ca.id as ca_assetId FROM chain_assets AS ca
|
||||
LEFT JOIN assets AS a ON a.assetId = ca.id AND a.chainId = ca.chainId AND a.metaId = :metaId
|
||||
INNER JOIN currencies as currency ON currency.selected = 1
|
||||
LEFT JOIN tokens AS t ON ca.symbol = t.tokenSymbol AND currency.id = t.currencyId
|
||||
WHERE ca.chainId || ':' || ca.id in (:joinedChainAndAssetIds)
|
||||
"""
|
||||
|
||||
interface AssetReadOnlyCache {
|
||||
|
||||
fun observeSyncedAssets(metaId: Long): Flow<List<AssetWithToken>>
|
||||
|
||||
suspend fun getSyncedAssets(metaId: Long): List<AssetWithToken>
|
||||
|
||||
fun observeSupportedAssets(metaId: Long): Flow<List<AssetWithToken>>
|
||||
|
||||
suspend fun getSupportedAssets(metaId: Long): List<AssetWithToken>
|
||||
|
||||
fun observeAsset(metaId: Long, chainId: String, assetId: Int): Flow<AssetWithToken>
|
||||
|
||||
fun observeAssetOrNull(metaId: Long, chainId: String, assetId: Int): Flow<AssetWithToken?>
|
||||
|
||||
fun observeAssets(metaId: Long, assetIds: Collection<AssetAndChainId>): Flow<List<AssetWithToken>>
|
||||
|
||||
suspend fun getAssetWithToken(metaId: Long, chainId: String, assetId: Int): AssetWithToken?
|
||||
|
||||
suspend fun getAsset(metaId: Long, chainId: String, assetId: Int): AssetLocal?
|
||||
|
||||
suspend fun getAssetsInChain(metaId: Long, chainId: String): List<AssetLocal>
|
||||
|
||||
suspend fun getAllAssets(): List<AssetLocal>
|
||||
|
||||
suspend fun getAssetsById(id: Int): List<AssetLocal>
|
||||
}
|
||||
|
||||
@Dao
|
||||
abstract class AssetDao : AssetReadOnlyCache {
|
||||
|
||||
@Query(RETRIEVE_SYNCED_ACCOUNT_ASSETS_QUERY)
|
||||
abstract override fun observeSyncedAssets(metaId: Long): Flow<List<AssetWithToken>>
|
||||
|
||||
@Query(RETRIEVE_SYNCED_ACCOUNT_ASSETS_QUERY)
|
||||
abstract override suspend fun getSyncedAssets(metaId: Long): List<AssetWithToken>
|
||||
|
||||
@Query(RETRIEVE_SUPPORTED_ACCOUNT_ASSETS_QUERY)
|
||||
abstract override fun observeSupportedAssets(metaId: Long): Flow<List<AssetWithToken>>
|
||||
|
||||
@Query(RETRIEVE_SUPPORTED_ACCOUNT_ASSETS_QUERY)
|
||||
abstract override suspend fun getSupportedAssets(metaId: Long): List<AssetWithToken>
|
||||
|
||||
@Query(RETRIEVE_ASSET_SQL_META_ID)
|
||||
abstract override fun observeAsset(metaId: Long, chainId: String, assetId: Int): Flow<AssetWithToken>
|
||||
|
||||
@Query(RETRIEVE_ASSET_SQL_META_ID)
|
||||
abstract override fun observeAssetOrNull(metaId: Long, chainId: String, assetId: Int): Flow<AssetWithToken?>
|
||||
|
||||
@Query(RETRIEVE_ASSET_SQL_META_ID)
|
||||
abstract override suspend fun getAssetWithToken(metaId: Long, chainId: String, assetId: Int): AssetWithToken?
|
||||
|
||||
@Query("SELECT * FROM assets WHERE metaId = :metaId AND chainId = :chainId AND assetId = :assetId")
|
||||
abstract override suspend fun getAsset(metaId: Long, chainId: String, assetId: Int): AssetLocal?
|
||||
|
||||
@Query("SELECT * FROM assets WHERE metaId = :metaId AND chainId = :chainId")
|
||||
abstract override suspend fun getAssetsInChain(metaId: Long, chainId: String): List<AssetLocal>
|
||||
|
||||
@Query("SELECT * FROM assets")
|
||||
abstract override suspend fun getAllAssets(): List<AssetLocal>
|
||||
|
||||
@Query("SELECT * FROM assets WHERE assetId IS :id")
|
||||
abstract override suspend fun getAssetsById(id: Int): List<AssetLocal>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertAsset(asset: AssetLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertAssets(assets: List<AssetLocal>)
|
||||
|
||||
@Delete(entity = AssetLocal::class)
|
||||
abstract suspend fun clearAssets(assetIds: List<ClearAssetsParams>)
|
||||
|
||||
@Query(RETRIEVE_ASSETS_SQL_META_ID)
|
||||
protected abstract fun observeJoinedAssets(metaId: Long, joinedChainAndAssetIds: Set<String>): Flow<List<AssetWithToken>>
|
||||
|
||||
override fun observeAssets(metaId: Long, assetIds: Collection<AssetAndChainId>): Flow<List<AssetWithToken>> {
|
||||
return flowOfAll {
|
||||
val joinedChainAndAssetIds = assetIds.mapToSet { (chainId, assetId) -> "$chainId:$assetId" }
|
||||
|
||||
observeJoinedAssets(metaId, joinedChainAndAssetIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ClearAssetsParams(val chainId: String, val assetId: Int)
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.BrowserHostSettingsLocal
|
||||
|
||||
@Dao
|
||||
abstract class BrowserHostSettingsDao {
|
||||
|
||||
@Query("SELECT * FROM browser_host_settings")
|
||||
abstract suspend fun getBrowserAllHostSettings(): List<BrowserHostSettingsLocal>
|
||||
|
||||
@Query("SELECT * FROM browser_host_settings WHERE hostUrl = :host")
|
||||
abstract suspend fun getBrowserHostSettings(host: String): BrowserHostSettingsLocal?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertBrowserHostSettings(settings: BrowserHostSettingsLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertBrowserHostSettings(settings: List<BrowserHostSettingsLocal>)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.BrowserTabLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class BrowserTabsDao {
|
||||
|
||||
@Query("SELECT id FROM browser_tabs WHERE metaId = :metaId")
|
||||
abstract fun getTabIdsFor(metaId: Long): List<String>
|
||||
|
||||
@Query("SELECT * FROM browser_tabs WHERE metaId = :metaId ORDER BY creationTime DESC")
|
||||
abstract fun observeTabsByMetaId(metaId: Long): Flow<List<BrowserTabLocal>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertTab(tab: BrowserTabLocal)
|
||||
|
||||
@Transaction
|
||||
open suspend fun removeTabsByMetaId(metaId: Long): List<String> {
|
||||
val tabIds = getTabIdsFor(metaId)
|
||||
removeTabsByIds(tabIds)
|
||||
return tabIds
|
||||
}
|
||||
|
||||
@Query("DELETE FROM browser_tabs WHERE id = :tabId")
|
||||
abstract suspend fun removeTab(tabId: String)
|
||||
|
||||
@Query("DELETE FROM browser_tabs WHERE id IN (:tabIds)")
|
||||
abstract suspend fun removeTabsByIds(tabIds: List<String>)
|
||||
|
||||
@Query("UPDATE browser_tabs SET pageName = :pageName, pageIconPath = :pageIconPath, pagePicturePath = :pagePicturePath WHERE id = :tabId")
|
||||
abstract suspend fun updatePageSnapshot(tabId: String, pageName: String?, pageIconPath: String?, pagePicturePath: String?)
|
||||
|
||||
@Query("UPDATE browser_tabs SET currentUrl = :url WHERE id = :tabId")
|
||||
abstract fun updateCurrentUrl(tabId: String, url: String)
|
||||
|
||||
@Query("UPDATE browser_tabs SET dappMetadata_iconLink = :dappIconUrl WHERE id = :tabId")
|
||||
abstract fun updateKnownDAppMetadata(tabId: String, dappIconUrl: String?)
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.chain.AssetSourceLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
|
||||
typealias FullAssetIdLocal = Pair<String, Int>
|
||||
|
||||
@Dao
|
||||
abstract class ChainAssetDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateAssets(diff: CollectionDiffer.Diff<ChainAssetLocal>) {
|
||||
insertAssets(diff.newOrUpdated)
|
||||
deleteChainAssets(diff.removed)
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM chain_assets WHERE id = :id AND chainId = :chainId")
|
||||
abstract suspend fun getAsset(id: Int, chainId: String): ChainAssetLocal?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertAsset(asset: ChainAssetLocal)
|
||||
|
||||
@Query("SELECT * FROM chain_assets WHERE source = :source")
|
||||
abstract suspend fun getAssetsBySource(source: AssetSourceLocal): List<ChainAssetLocal>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun insertAssets(assets: List<ChainAssetLocal>)
|
||||
|
||||
@Query("UPDATE chain_assets SET enabled = :enabled WHERE chainId = :chainId AND id = :assetId")
|
||||
protected abstract suspend fun setAssetEnabled(enabled: Boolean, chainId: String, assetId: Int)
|
||||
|
||||
@Query("SELECT * FROM chain_assets WHERE enabled=1")
|
||||
abstract suspend fun getEnabledAssets(): List<ChainAssetLocal>
|
||||
|
||||
@Update(entity = ChainAssetLocal::class)
|
||||
abstract suspend fun setAssetsEnabled(params: List<SetAssetEnabledParams>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteChainAssets(assets: List<ChainAssetLocal>)
|
||||
}
|
||||
|
||||
class SetAssetEnabledParams(val enabled: Boolean, val chainId: String, val id: Int)
|
||||
@@ -0,0 +1,245 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExplorerLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainExternalApiLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainNodeLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainRuntimeInfoLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.JoinedChainInfo
|
||||
import io.novafoundation.nova.core_db.model.chain.NodeSelectionPreferencesLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class ChainDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun applyDiff(
|
||||
chainDiff: CollectionDiffer.Diff<ChainLocal>,
|
||||
assetsDiff: CollectionDiffer.Diff<ChainAssetLocal>,
|
||||
nodesDiff: CollectionDiffer.Diff<ChainNodeLocal>,
|
||||
explorersDiff: CollectionDiffer.Diff<ChainExplorerLocal>,
|
||||
externalApisDiff: CollectionDiffer.Diff<ChainExternalApiLocal>,
|
||||
nodeSelectionPreferencesDiff: CollectionDiffer.Diff<NodeSelectionPreferencesLocal>
|
||||
) {
|
||||
deleteChains(chainDiff.removed)
|
||||
deleteChainAssets(assetsDiff.removed)
|
||||
deleteChainNodes(nodesDiff.removed)
|
||||
deleteChainExplorers(explorersDiff.removed)
|
||||
deleteExternalApis(externalApisDiff.removed)
|
||||
deleteNodePreferences(nodeSelectionPreferencesDiff.removed)
|
||||
|
||||
addChains(chainDiff.added)
|
||||
addChainAssets(assetsDiff.added)
|
||||
addChainNodes(nodesDiff.added)
|
||||
addChainExplorers(explorersDiff.added)
|
||||
addExternalApis(externalApisDiff.added)
|
||||
addNodePreferences(nodeSelectionPreferencesDiff.added)
|
||||
|
||||
updateChains(chainDiff.updated)
|
||||
updateChainAssets(assetsDiff.updated)
|
||||
updateChainNodes(nodesDiff.updated)
|
||||
updateChainExplorers(explorersDiff.updated)
|
||||
updateExternalApis(externalApisDiff.updated)
|
||||
updateNodePreferences(nodeSelectionPreferencesDiff.added)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open suspend fun addChainOrUpdate(
|
||||
chain: ChainLocal,
|
||||
assets: List<ChainAssetLocal>,
|
||||
nodes: List<ChainNodeLocal>,
|
||||
explorers: List<ChainExplorerLocal>,
|
||||
externalApis: List<ChainExternalApiLocal>,
|
||||
nodeSelectionPreferences: NodeSelectionPreferencesLocal
|
||||
) {
|
||||
addChainOrUpdate(chain)
|
||||
addChainAssetsOrUpdate(assets)
|
||||
addChainNodesOrUpdate(nodes)
|
||||
addChainExplorersOrUpdate(explorers)
|
||||
addExternalApisOrUpdate(externalApis)
|
||||
addNodePreferencesOrUpdate(nodeSelectionPreferences)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open suspend fun editChain(
|
||||
chainId: String,
|
||||
assetId: Int,
|
||||
chainName: String,
|
||||
symbol: String,
|
||||
explorer: ChainExplorerLocal?,
|
||||
priceId: String?
|
||||
) {
|
||||
updateChainName(chainId, chainName)
|
||||
updateAssetToken(chainId, assetId, symbol, priceId)
|
||||
addChainExplorersOrUpdate(listOfNotNull(explorer))
|
||||
}
|
||||
|
||||
// ------ Delete --------
|
||||
@Delete
|
||||
protected abstract suspend fun deleteChains(chains: List<ChainLocal>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteChainNodes(nodes: List<ChainNodeLocal>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteChainAssets(assets: List<ChainAssetLocal>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteChainExplorers(explorers: List<ChainExplorerLocal>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteExternalApis(apis: List<ChainExternalApiLocal>)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteNodePreferences(apis: List<NodeSelectionPreferencesLocal>)
|
||||
|
||||
// ------ Add --------
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addChains(chains: List<ChainLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addChainNodes(nodes: List<ChainNodeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addChainAssets(assets: List<ChainAssetLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addChainExplorers(explorers: List<ChainExplorerLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addExternalApis(apis: List<ChainExternalApiLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun addChainOrUpdate(node: ChainLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
abstract suspend fun addChainNode(node: ChainNodeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun addNodePreferences(model: List<NodeSelectionPreferencesLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun addNodePreferencesOrUpdate(model: NodeSelectionPreferencesLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun addChainNodesOrUpdate(nodes: List<ChainNodeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun addChainAssetsOrUpdate(assets: List<ChainAssetLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun addChainExplorersOrUpdate(explorers: List<ChainExplorerLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun addExternalApisOrUpdate(apis: List<ChainExternalApiLocal>)
|
||||
|
||||
// ------ Update -----
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateChains(chains: List<ChainLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateChainNodes(nodes: List<ChainNodeLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateChainAssets(assets: List<ChainAssetLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateChainExplorers(explorers: List<ChainExplorerLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateExternalApis(apis: List<ChainExternalApiLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateNodePreferences(apis: List<NodeSelectionPreferencesLocal>)
|
||||
|
||||
// ------- Queries ------
|
||||
|
||||
@Query("SELECT * FROM chains")
|
||||
@Transaction
|
||||
abstract suspend fun getJoinChainInfo(): List<JoinedChainInfo>
|
||||
|
||||
@Query("SELECT id FROM chains")
|
||||
@Transaction
|
||||
abstract suspend fun getAllChainIds(): List<String>
|
||||
|
||||
@Query("SELECT * FROM chains")
|
||||
@Transaction
|
||||
abstract fun joinChainInfoFlow(): Flow<List<JoinedChainInfo>>
|
||||
|
||||
@Query("SELECT orderId FROM chain_nodes WHERE chainId = :chainId ORDER BY orderId DESC LIMIT 1")
|
||||
abstract suspend fun getLastChainNodeOrderId(chainId: String): Int
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM chains WHERE id = :chainId)")
|
||||
abstract suspend fun chainExists(chainId: String): Boolean
|
||||
|
||||
@Query("SELECT * FROM chain_runtimes WHERE chainId = :chainId")
|
||||
abstract suspend fun runtimeInfo(chainId: String): ChainRuntimeInfoLocal?
|
||||
|
||||
@Query("SELECT * FROM chain_runtimes")
|
||||
abstract suspend fun allRuntimeInfos(): List<ChainRuntimeInfoLocal>
|
||||
|
||||
@Query("UPDATE chain_runtimes SET syncedVersion = :syncedVersion, localMigratorVersion = :localMigratorVersion WHERE chainId = :chainId")
|
||||
abstract suspend fun updateSyncedRuntimeVersion(chainId: String, syncedVersion: Int, localMigratorVersion: Int)
|
||||
|
||||
@Query("UPDATE chains SET connectionState = :connectionState WHERE id = :chainId")
|
||||
abstract suspend fun setConnectionState(chainId: String, connectionState: ChainLocal.ConnectionStateLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun setNodePreferences(model: NodeSelectionPreferencesLocal)
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateRemoteRuntimeVersionIfChainExists(
|
||||
chainId: String,
|
||||
runtimeVersion: Int,
|
||||
transactionVersion: Int,
|
||||
) {
|
||||
if (!chainExists(chainId)) return
|
||||
|
||||
if (isRuntimeInfoExists(chainId)) {
|
||||
updateRemoteRuntimeVersionUnsafe(chainId, runtimeVersion, transactionVersion)
|
||||
} else {
|
||||
val runtimeInfoLocal = ChainRuntimeInfoLocal(
|
||||
chainId,
|
||||
syncedVersion = 0,
|
||||
remoteVersion = runtimeVersion,
|
||||
transactionVersion = transactionVersion,
|
||||
localMigratorVersion = 1
|
||||
)
|
||||
insertRuntimeInfo(runtimeInfoLocal)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("UPDATE chain_nodes SET url = :newUrl, name = :name WHERE chainId = :chainId AND url = :oldUrl")
|
||||
abstract suspend fun updateChainNode(chainId: String, oldUrl: String, newUrl: String, name: String)
|
||||
|
||||
@Query("UPDATE chain_runtimes SET remoteVersion = :remoteVersion, transactionVersion = :transactionVersion WHERE chainId = :chainId")
|
||||
protected abstract suspend fun updateRemoteRuntimeVersionUnsafe(chainId: String, remoteVersion: Int, transactionVersion: Int)
|
||||
|
||||
@Query("SELECT EXISTS (SELECT * FROM chain_runtimes WHERE chainId = :chainId)")
|
||||
protected abstract suspend fun isRuntimeInfoExists(chainId: String): Boolean
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun insertRuntimeInfo(runtimeInfoLocal: ChainRuntimeInfoLocal)
|
||||
|
||||
@Query("UPDATE chains SET name = :name WHERE id = :chainId")
|
||||
abstract suspend fun updateChainName(chainId: String, name: String)
|
||||
|
||||
@Query("UPDATE chain_assets SET symbol = :symbol, priceId = :priceId WHERE chainId = :chainId and id == :assetId")
|
||||
abstract suspend fun updateAssetToken(chainId: String, assetId: Int, symbol: String, priceId: String?)
|
||||
|
||||
@Query("DELETE FROM chains WHERE id = :chainId")
|
||||
abstract suspend fun deleteChain(chainId: String)
|
||||
|
||||
@Query("DELETE FROM chain_nodes WHERE chainId = :chainId AND url = :url")
|
||||
abstract suspend fun deleteNode(chainId: String, url: String)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.CoinPriceLocal
|
||||
|
||||
@Dao
|
||||
interface CoinPriceDao {
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM coin_prices
|
||||
WHERE priceId = :priceId AND currencyId = :currencyId
|
||||
AND timestamp <= :timestamp
|
||||
ORDER BY timestamp DESC LIMIT 1
|
||||
"""
|
||||
)
|
||||
suspend fun getFloorCoinPriceAtTime(priceId: String, currencyId: String, timestamp: Long): CoinPriceLocal?
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT EXISTS(
|
||||
SELECT * FROM coin_prices
|
||||
WHERE priceId = :priceId AND currencyId = :currencyId
|
||||
AND timestamp >= :timestamp
|
||||
ORDER BY timestamp ASC LIMIT 1
|
||||
)
|
||||
"""
|
||||
)
|
||||
suspend fun hasCeilingCoinPriceAtTime(priceId: String, currencyId: String, timestamp: Long): Boolean
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM coin_prices
|
||||
WHERE priceId = :priceId AND currencyId = :currencyId
|
||||
AND timestamp BETWEEN :fromTimestamp AND :toTimestamp
|
||||
ORDER BY timestamp ASC
|
||||
"""
|
||||
)
|
||||
suspend fun getCoinPriceRange(priceId: String, currencyId: String, fromTimestamp: Long, toTimestamp: Long): List<CoinPriceLocal>
|
||||
|
||||
@Transaction
|
||||
suspend fun updateCoinPrices(priceId: String, currencyId: String, coinRates: List<CoinPriceLocal>) {
|
||||
deleteCoinPrices(priceId, currencyId)
|
||||
setCoinPrices(coinRates)
|
||||
}
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun setCoinPrices(coinPrices: List<CoinPriceLocal>)
|
||||
|
||||
@Query(
|
||||
"""
|
||||
DELETE FROM coin_prices
|
||||
WHERE priceId = :priceId AND currencyId = :currencyId
|
||||
"""
|
||||
)
|
||||
fun deleteCoinPrices(priceId: String, currencyId: String)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.ContributionLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class ContributionDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateContributions(contributions: CollectionDiffer.Diff<ContributionLocal>) {
|
||||
insertContributions(contributions.added)
|
||||
updateContributions(contributions.updated)
|
||||
deleteContributions(contributions.removed)
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM contributions WHERE metaId = :metaId AND chainId = :chainId AND assetId = :assetId")
|
||||
abstract fun observeContributions(metaId: Long, chainId: String, assetId: Int): Flow<List<ContributionLocal>>
|
||||
|
||||
@Query("SELECT * FROM contributions WHERE metaId = :metaId")
|
||||
abstract fun observeContributions(metaId: Long): Flow<List<ContributionLocal>>
|
||||
|
||||
@Query("SELECT * FROM contributions WHERE metaId = :metaId AND chainId = :chainId AND assetId = :assetId AND sourceId = :sourceId")
|
||||
abstract suspend fun getContributions(metaId: Long, chainId: String, assetId: Int, sourceId: String): List<ContributionLocal>
|
||||
|
||||
@Query("DELETE FROM contributions WHERE chainId = :chainId AND assetId = :assetId")
|
||||
abstract suspend fun deleteContributions(chainId: String, assetId: Int)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteContributions(contributions: List<ContributionLocal>)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun updateContributions(contributions: List<ContributionLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun insertContributions(contributions: List<ContributionLocal>)
|
||||
|
||||
@Delete(entity = ContributionLocal::class)
|
||||
abstract suspend fun deleteAssetContributions(params: List<DeleteAssetContributionsParams>)
|
||||
}
|
||||
|
||||
class DeleteAssetContributionsParams(val chainId: String, val assetId: Int)
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.CurrencyLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
private const val RETRIEVE_CURRENCIES = "SELECT * FROM currencies"
|
||||
|
||||
private const val RETRIEVE_SELECTED_CURRENCY = "SELECT * FROM currencies WHERE selected = 1"
|
||||
|
||||
@Dao
|
||||
abstract class CurrencyDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateCurrencies(currencies: CollectionDiffer.Diff<CurrencyLocal>) {
|
||||
deleteCurrencies(currencies.removed)
|
||||
insertCurrencies(currencies.added)
|
||||
updateCurrencies(currencies.updated)
|
||||
|
||||
if (getSelectedCurrency() == null) {
|
||||
selectCurrency(0)
|
||||
}
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM currencies WHERE id = 0")
|
||||
abstract fun getFirst(): CurrencyLocal
|
||||
|
||||
@Query(RETRIEVE_CURRENCIES)
|
||||
abstract suspend fun getCurrencies(): List<CurrencyLocal>
|
||||
|
||||
@Query(RETRIEVE_CURRENCIES)
|
||||
abstract fun observeCurrencies(): Flow<List<CurrencyLocal>>
|
||||
|
||||
@Query(RETRIEVE_SELECTED_CURRENCY)
|
||||
abstract suspend fun getSelectedCurrency(): CurrencyLocal?
|
||||
|
||||
@Query(RETRIEVE_SELECTED_CURRENCY)
|
||||
abstract fun observeSelectCurrency(): Flow<CurrencyLocal>
|
||||
|
||||
@Query("UPDATE currencies SET selected = (id = :currencyId)")
|
||||
abstract fun selectCurrency(currencyId: Int)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
abstract suspend fun insert(currency: CurrencyLocal)
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteCurrencies(currencies: List<CurrencyLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
protected abstract suspend fun insertCurrencies(currencies: List<CurrencyLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateCurrencies(currencies: List<CurrencyLocal>)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.DappAuthorizationLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface DappAuthorizationDao {
|
||||
|
||||
@Query("SELECT * FROM dapp_authorizations WHERE baseUrl = :baseUrl AND metaId = :metaId")
|
||||
suspend fun getAuthorization(baseUrl: String, metaId: Long): DappAuthorizationLocal?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun updateAuthorization(dappAuthorization: DappAuthorizationLocal)
|
||||
|
||||
@Query("UPDATE dapp_authorizations SET authorized = 0 WHERE baseUrl = :baseUrl AND metaId = :metaId")
|
||||
suspend fun removeAuthorization(baseUrl: String, metaId: Long)
|
||||
|
||||
@Query("SELECT * FROM dapp_authorizations WHERE metaId = :metaId")
|
||||
fun observeAuthorizations(metaId: Long): Flow<List<DappAuthorizationLocal>>
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.AggregatedExternalBalanceLocal
|
||||
import io.novafoundation.nova.core_db.model.ExternalBalanceLocal
|
||||
import io.novasama.substrate_sdk_android.hash.isPositive
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ExternalBalanceDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertExternalBalance(externalBalance: ExternalBalanceLocal)
|
||||
|
||||
@Query("DELETE FROM externalBalances WHERE metaId = :metaId AND chainId = :chainId AND assetId = :assetId AND type = :type AND subtype = :subtype")
|
||||
suspend fun removeExternalBalance(
|
||||
metaId: Long,
|
||||
chainId: String,
|
||||
assetId: Int,
|
||||
type: ExternalBalanceLocal.Type,
|
||||
subtype: String?,
|
||||
)
|
||||
|
||||
@Delete(entity = ExternalBalanceLocal::class)
|
||||
suspend fun deleteAssetExternalBalances(params: List<ExternalBalanceAssetDeleteParams>)
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT chainId, assetId, type, SUM(amount) as aggregatedAmount
|
||||
FROM externalBalances
|
||||
WHERE metaId = :metaId
|
||||
GROUP BY chainId, assetId, type
|
||||
"""
|
||||
)
|
||||
fun observeAggregatedExternalBalances(metaId: Long): Flow<List<AggregatedExternalBalanceLocal>>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT chainId, assetId, type, SUM(amount) as aggregatedAmount
|
||||
FROM externalBalances
|
||||
WHERE metaId = :metaId AND chainId = :chainId AND assetId = :assetId
|
||||
GROUP BY type
|
||||
"""
|
||||
)
|
||||
fun observeChainAggregatedExternalBalances(metaId: Long, chainId: String, assetId: Int): Flow<List<AggregatedExternalBalanceLocal>>
|
||||
}
|
||||
|
||||
suspend fun ExternalBalanceDao.updateExternalBalance(externalBalance: ExternalBalanceLocal) {
|
||||
if (externalBalance.amount.isPositive()) {
|
||||
insertExternalBalance(externalBalance)
|
||||
} else {
|
||||
removeExternalBalance(
|
||||
metaId = externalBalance.metaId,
|
||||
chainId = externalBalance.chainId,
|
||||
assetId = externalBalance.assetId,
|
||||
type = externalBalance.type,
|
||||
subtype = externalBalance.subtype
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalBalanceAssetDeleteParams(val chainId: String, val assetId: Int)
|
||||
@@ -0,0 +1,34 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.core_db.model.FavouriteDAppLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface FavouriteDAppsDao {
|
||||
|
||||
@Query("SELECT * FROM favourite_dapps")
|
||||
fun observeFavouriteDApps(): Flow<List<FavouriteDAppLocal>>
|
||||
|
||||
@Query("SELECT * FROM favourite_dapps")
|
||||
suspend fun getFavouriteDApps(): List<FavouriteDAppLocal>
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM favourite_dapps WHERE url = :dAppUrl)")
|
||||
fun observeIsFavourite(dAppUrl: String): Flow<Boolean>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertFavouriteDApp(dApp: FavouriteDAppLocal)
|
||||
|
||||
@Query("DELETE FROM favourite_dapps WHERE url = :dAppUrl")
|
||||
suspend fun deleteFavouriteDApp(dAppUrl: String)
|
||||
|
||||
@Update(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun updateFavourites(dapps: List<FavouriteDAppLocal>)
|
||||
|
||||
@Query("SELECT MAX(orderingIndex) FROM favourite_dapps")
|
||||
suspend fun getMaxOrderingIndex(): Int
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.GiftLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface GiftsDao {
|
||||
|
||||
@Query("SELECT * from gifts WHERE id = :id")
|
||||
suspend fun getGiftById(id: Long): GiftLocal
|
||||
|
||||
@Query("SELECT * from gifts")
|
||||
suspend fun getAllGifts(): List<GiftLocal>
|
||||
|
||||
@Query("SELECT * from gifts WHERE id = :id")
|
||||
fun observeGiftById(id: Long): Flow<GiftLocal>
|
||||
|
||||
@Query("SELECT * from gifts")
|
||||
fun observeAllGifts(): Flow<List<GiftLocal>>
|
||||
|
||||
@Query("SELECT * from gifts WHERE chainId = :chainId AND assetId = :assetId")
|
||||
fun observeGiftsByAsset(chainId: String, assetId: Int): Flow<List<GiftLocal>>
|
||||
|
||||
@Insert
|
||||
suspend fun createNewGift(giftLocal: GiftLocal): Long
|
||||
|
||||
@Query("UPDATE gifts SET status = :status WHERE id = :id")
|
||||
suspend fun setGiftState(id: Long, status: GiftLocal.Status)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.GovernanceDAppLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class GovernanceDAppsDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun update(newDapps: List<GovernanceDAppLocal>) {
|
||||
val oldDapps = getAll()
|
||||
val dappDiffs = CollectionDiffer.findDiff(newDapps, oldDapps, false)
|
||||
|
||||
deleteDapps(dappDiffs.removed)
|
||||
updateDapps(dappDiffs.updated)
|
||||
insertDapps(dappDiffs.added)
|
||||
}
|
||||
|
||||
@Query("SELECT * FROM governance_dapps")
|
||||
abstract fun getAll(): List<GovernanceDAppLocal>
|
||||
|
||||
@Query("SELECT * FROM governance_dapps WHERE chainId = :chainId")
|
||||
abstract fun observeChainDapps(chainId: String): Flow<List<GovernanceDAppLocal>>
|
||||
|
||||
@Delete
|
||||
abstract suspend fun deleteDapps(dapps: List<GovernanceDAppLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.ABORT)
|
||||
abstract suspend fun insertDapps(dapps: List<GovernanceDAppLocal>)
|
||||
|
||||
@Update
|
||||
abstract suspend fun updateDapps(dapps: List<GovernanceDAppLocal>)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.BalanceHoldLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class HoldsDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateHolds(
|
||||
holds: List<BalanceHoldLocal>,
|
||||
metaId: Long,
|
||||
chainId: String,
|
||||
chainAssetId: Int
|
||||
) {
|
||||
deleteHolds(metaId, chainId, chainAssetId)
|
||||
|
||||
insert(holds)
|
||||
}
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract fun insert(holds: List<BalanceHoldLocal>)
|
||||
|
||||
@Query("DELETE FROM holds WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
|
||||
protected abstract fun deleteHolds(metaId: Long, chainId: String, chainAssetId: Int)
|
||||
|
||||
@Query("SELECT * FROM holds WHERE metaId = :metaId")
|
||||
abstract fun observeHoldsForMetaAccount(metaId: Long): Flow<List<BalanceHoldLocal>>
|
||||
|
||||
@Query("SELECT * FROM holds WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
|
||||
abstract fun observeBalanceHolds(metaId: Long, chainId: String, chainAssetId: Int): Flow<List<BalanceHoldLocal>>
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.BalanceLockLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class LockDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateLocks(
|
||||
locks: List<BalanceLockLocal>,
|
||||
metaId: Long,
|
||||
chainId: String,
|
||||
chainAssetId: Int
|
||||
) {
|
||||
deleteLocks(metaId, chainId, chainAssetId)
|
||||
|
||||
insert(locks)
|
||||
}
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract fun insert(locks: List<BalanceLockLocal>)
|
||||
|
||||
@Query("DELETE FROM locks WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
|
||||
abstract fun deleteLocks(metaId: Long, chainId: String, chainAssetId: Int)
|
||||
|
||||
@Query("SELECT * FROM locks WHERE metaId = :metaId")
|
||||
abstract fun observeLocksForMetaAccount(metaId: Long): Flow<List<BalanceLockLocal>>
|
||||
|
||||
@Query("SELECT * FROM locks WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
|
||||
abstract fun observeBalanceLocks(metaId: Long, chainId: String, chainAssetId: Int): Flow<List<BalanceLockLocal>>
|
||||
|
||||
@Query("SELECT * FROM locks WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId")
|
||||
abstract suspend fun getBalanceLocks(metaId: Long, chainId: String, chainAssetId: Int): List<BalanceLockLocal>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM locks
|
||||
WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId
|
||||
ORDER BY amount DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
)
|
||||
abstract suspend fun getBiggestBalanceLock(metaId: Long, chainId: String, chainAssetId: Int): BalanceLockLocal?
|
||||
|
||||
@Query("SELECT * FROM locks WHERE metaId = :metaId AND chainId = :chainId AND assetId = :chainAssetId AND type = :lockId")
|
||||
abstract fun observeBalanceLock(metaId: Long, chainId: String, chainAssetId: Int, lockId: String): Flow<BalanceLockLocal?>
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.core_db.model.chain.account.ChainAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountIdWithType
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountPositionUpdate
|
||||
import io.novafoundation.nova.core_db.model.chain.account.ProxyAccountLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.account.RelationJoinedMetaAccountInfo
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.intellij.lang.annotations.Language
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/**
|
||||
* Fetch meta account where either
|
||||
* 1. chain account for specified chain is present and its accountId matches
|
||||
* 2. chain account for specified is missing but one of base accountIds matches
|
||||
*
|
||||
* Note that if both chain account and base accounts are present than we should filter out entries where chain account matches but base accounts does not
|
||||
*/
|
||||
@Language("RoomSql")
|
||||
private const val FIND_BY_ADDRESS_WHERE_CLAUSE = """
|
||||
LEFT JOIN chain_accounts as c ON m.id = c.metaId AND c.chainId = :chainId
|
||||
WHERE
|
||||
(c.accountId IS NOT NULL AND c.accountId = :accountId)
|
||||
OR (c.accountId IS NULL AND (substrateAccountId = :accountId OR ethereumAddress = :accountId))
|
||||
ORDER BY (CASE WHEN isSelected THEN 0 ELSE 1 END)
|
||||
"""
|
||||
|
||||
@Language("RoomSql")
|
||||
private const val FIND_ACCOUNT_BY_ADDRESS_QUERY = """
|
||||
SELECT * FROM meta_accounts as m
|
||||
$FIND_BY_ADDRESS_WHERE_CLAUSE
|
||||
"""
|
||||
|
||||
@Language("RoomSql")
|
||||
private const val FIND_NAME_BY_ADDRESS_QUERY = """
|
||||
SELECT name FROM meta_accounts as m
|
||||
$FIND_BY_ADDRESS_WHERE_CLAUSE
|
||||
"""
|
||||
|
||||
@Language("RoomSql")
|
||||
private const val META_ACCOUNTS_WITH_BALANCE_PART = """
|
||||
SELECT
|
||||
m.id,
|
||||
a.freeInPlanks,
|
||||
a.reservedInPlanks,
|
||||
(SELECT SUM(amountInPlanks) FROM contributions WHERE chainId = a.chainId AND assetId = a.assetId AND metaId = m.id) offChainBalance,
|
||||
ca.precision,
|
||||
t.rate
|
||||
FROM meta_accounts as m
|
||||
INNER JOIN assets as a ON a.metaId = m.id
|
||||
INNER JOIN chain_assets AS ca ON a.assetId = ca.id AND a.chainId = ca.chainId
|
||||
INNER JOIN currencies as currency ON currency.selected = 1
|
||||
INNER JOIN tokens as t ON t.tokenSymbol = ca.symbol AND t.currencyId = currency.id
|
||||
"""
|
||||
|
||||
@Language("RoomSql")
|
||||
private const val META_ACCOUNTS_WITH_BALANCE_QUERY = """
|
||||
$META_ACCOUNTS_WITH_BALANCE_PART
|
||||
ORDER BY m.position
|
||||
"""
|
||||
|
||||
@Language("RoomSql")
|
||||
private const val META_ACCOUNT_WITH_BALANCE_QUERY = """
|
||||
$META_ACCOUNTS_WITH_BALANCE_PART
|
||||
WHERE m.id == :metaId
|
||||
"""
|
||||
|
||||
@Dao
|
||||
interface MetaAccountDao {
|
||||
|
||||
@Transaction
|
||||
suspend fun insertProxiedMetaAccount(
|
||||
metaAccount: MetaAccountLocal,
|
||||
chainAccount: (metaId: Long) -> ChainAccountLocal,
|
||||
proxyAccount: (metaId: Long) -> ProxyAccountLocal
|
||||
): Long {
|
||||
val metaId = insertMetaAccount(metaAccount)
|
||||
insertChainAccount(chainAccount(metaId))
|
||||
insertProxy(proxyAccount(metaId))
|
||||
|
||||
return metaId
|
||||
}
|
||||
|
||||
@Transaction
|
||||
suspend fun runInTransaction(action: suspend () -> Unit) {
|
||||
action()
|
||||
}
|
||||
|
||||
@Insert
|
||||
suspend fun insertMetaAccount(metaAccount: MetaAccountLocal): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun updateMetaAccount(metaAccount: MetaAccountLocal): Long
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertChainAccount(chainAccount: ChainAccountLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertChainAccounts(chainAccounts: List<ChainAccountLocal>)
|
||||
|
||||
@Delete
|
||||
suspend fun deleteChainAccounts(chainAccounts: List<ChainAccountLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertProxy(proxyLocal: ProxyAccountLocal)
|
||||
|
||||
@Query("SELECT * FROM meta_accounts")
|
||||
suspend fun getMetaAccounts(): List<MetaAccountLocal>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE id IN (:metaIds)")
|
||||
suspend fun getMetaAccountsByIds(metaIds: List<Long>): List<RelationJoinedMetaAccountInfo>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE id = :id")
|
||||
suspend fun getMetaAccount(id: Long): MetaAccountLocal?
|
||||
|
||||
@Query("SELECT COUNT(*) FROM meta_accounts WHERE status = :status")
|
||||
@Transaction
|
||||
suspend fun getMetaAccountsQuantityByStatus(status: MetaAccountLocal.Status): Int
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE status = :status")
|
||||
@Transaction
|
||||
suspend fun getMetaAccountsByStatus(status: MetaAccountLocal.Status): List<RelationJoinedMetaAccountInfo>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts")
|
||||
@Transaction
|
||||
suspend fun getFullMetaAccounts(): List<RelationJoinedMetaAccountInfo>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts")
|
||||
fun getJoinedMetaAccountsInfoFlow(): Flow<List<RelationJoinedMetaAccountInfo>>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE status = :status")
|
||||
fun getJoinedMetaAccountsInfoByStatusFlow(status: MetaAccountLocal.Status): Flow<List<RelationJoinedMetaAccountInfo>>
|
||||
|
||||
@Query("SELECT id FROM meta_accounts WHERE status = :status")
|
||||
fun getMetaAccountsIdsByStatus(status: MetaAccountLocal.Status): List<Long>
|
||||
|
||||
@Query(META_ACCOUNTS_WITH_BALANCE_QUERY)
|
||||
fun metaAccountsWithBalanceFlow(): Flow<List<MetaAccountWithBalanceLocal>>
|
||||
|
||||
@Query(META_ACCOUNT_WITH_BALANCE_QUERY)
|
||||
fun metaAccountWithBalanceFlow(metaId: Long): Flow<List<MetaAccountWithBalanceLocal>>
|
||||
|
||||
@Query("UPDATE meta_accounts SET isSelected = (id = :metaId)")
|
||||
suspend fun selectMetaAccount(metaId: Long)
|
||||
|
||||
@Update(entity = MetaAccountLocal::class)
|
||||
suspend fun updatePositions(updates: List<MetaAccountPositionUpdate>)
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE id = :metaId")
|
||||
@Transaction
|
||||
suspend fun getJoinedMetaAccountInfo(metaId: Long): RelationJoinedMetaAccountInfo
|
||||
|
||||
@Query("SELECT type FROM meta_accounts WHERE id = :metaId")
|
||||
suspend fun getMetaAccountType(metaId: Long): MetaAccountLocal.Type?
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE isSelected = 1")
|
||||
@Transaction
|
||||
fun selectedMetaAccountInfoFlow(): Flow<RelationJoinedMetaAccountInfo?>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE id = :metaId")
|
||||
@Transaction
|
||||
fun metaAccountInfoFlow(metaId: Long): Flow<RelationJoinedMetaAccountInfo?>
|
||||
|
||||
@Query("SELECT EXISTS ($FIND_ACCOUNT_BY_ADDRESS_QUERY)")
|
||||
fun isMetaAccountExists(accountId: AccountId, chainId: String): Boolean
|
||||
|
||||
@Query(FIND_ACCOUNT_BY_ADDRESS_QUERY)
|
||||
@Transaction
|
||||
fun getMetaAccountInfo(accountId: AccountId, chainId: String): RelationJoinedMetaAccountInfo?
|
||||
|
||||
@Query(FIND_NAME_BY_ADDRESS_QUERY)
|
||||
fun metaAccountNameFor(accountId: AccountId, chainId: String): String?
|
||||
|
||||
@Query("UPDATE meta_accounts SET name = :newName WHERE id = :metaId")
|
||||
suspend fun updateName(metaId: Long, newName: String)
|
||||
|
||||
@Query(
|
||||
"""
|
||||
WITH RECURSIVE accounts_to_delete AS (
|
||||
SELECT id, parentMetaId, type FROM meta_accounts WHERE id IN (:metaIds)
|
||||
UNION ALL
|
||||
SELECT m.id, m.parentMetaId, m.type
|
||||
FROM meta_accounts m
|
||||
JOIN accounts_to_delete r ON m.parentMetaId = r.id
|
||||
)
|
||||
SELECT id, type FROM accounts_to_delete
|
||||
"""
|
||||
)
|
||||
suspend fun findAffectedMetaIdsOnDelete(metaIds: List<Long>): List<MetaAccountIdWithType>
|
||||
|
||||
@Query("DELETE FROM meta_accounts WHERE id IN (:ids)")
|
||||
suspend fun deleteByIds(ids: List<Long>)
|
||||
|
||||
@Transaction
|
||||
suspend fun delete(vararg metaId: Long): List<MetaAccountIdWithType> {
|
||||
val affectingMetaAccounts = findAffectedMetaIdsOnDelete(metaId.toList())
|
||||
if (affectingMetaAccounts.isNotEmpty()) {
|
||||
val ids = affectingMetaAccounts.map { it.id }
|
||||
deleteByIds(ids)
|
||||
}
|
||||
return affectingMetaAccounts
|
||||
}
|
||||
|
||||
@Transaction
|
||||
suspend fun delete(metaIds: List<Long>): List<MetaAccountIdWithType> {
|
||||
return delete(*metaIds.toLongArray())
|
||||
}
|
||||
|
||||
@Query("SELECT COALESCE(MAX(position), 0) + 1 FROM meta_accounts")
|
||||
suspend fun nextAccountPosition(): Int
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE isSelected = 1")
|
||||
suspend fun selectedMetaAccount(): RelationJoinedMetaAccountInfo?
|
||||
|
||||
@Query("SELECT EXISTS(SELECT id FROM meta_accounts WHERE type = :type)")
|
||||
fun hasMetaAccountsCountOfTypeFlow(type: MetaAccountLocal.Type): Flow<Boolean>
|
||||
|
||||
@Query("SELECT * FROM meta_accounts WHERE type = :type")
|
||||
fun observeMetaAccountsByTypeFlow(type: MetaAccountLocal.Type): Flow<List<RelationJoinedMetaAccountInfo>>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
DELETE FROM meta_accounts
|
||||
WHERE id IN (
|
||||
SELECT proxiedMetaId
|
||||
FROM proxy_accounts
|
||||
WHERE chainId = :chainId
|
||||
)
|
||||
"""
|
||||
)
|
||||
fun deleteProxiedMetaAccountsByChain(chainId: String)
|
||||
|
||||
@Transaction
|
||||
suspend fun insertMetaAndChainAccounts(
|
||||
metaAccount: MetaAccountLocal,
|
||||
createChainAccounts: suspend (metaId: Long) -> List<ChainAccountLocal>
|
||||
): Long {
|
||||
val metaId = insertMetaAccount(metaAccount)
|
||||
|
||||
insertChainAccounts(createChainAccounts(metaId))
|
||||
|
||||
return metaId
|
||||
}
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM meta_accounts WHERE status = :status)")
|
||||
suspend fun hasMetaAccountsByStatus(status: MetaAccountLocal.Status): Boolean
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM meta_accounts WHERE type = :type)")
|
||||
suspend fun hasMetaAccountsByType(type: MetaAccountLocal.Type): Boolean
|
||||
|
||||
@Query("SELECT EXISTS(SELECT * FROM meta_accounts WHERE id IN (:metaIds) AND type = :type)")
|
||||
suspend fun hasMetaAccountsByType(metaIds: Set<Long>, type: MetaAccountLocal.Type): Boolean
|
||||
|
||||
@Query("UPDATE meta_accounts SET status = :status WHERE id IN (:metaIds)")
|
||||
suspend fun changeAccountsStatus(metaIds: List<Long>, status: MetaAccountLocal.Status)
|
||||
|
||||
@Query("DELETE FROM meta_accounts WHERE status = :status ")
|
||||
fun removeMetaAccountsByStatus(status: MetaAccountLocal.Status)
|
||||
}
|
||||
|
||||
suspend inline fun <T : Any> MetaAccountDao.withTransaction(crossinline action: suspend () -> T): T {
|
||||
var result: T? = null
|
||||
|
||||
runInTransaction {
|
||||
result = action()
|
||||
}
|
||||
|
||||
return result!!
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
suspend fun MetaAccountDao.updateMetaAccount(metaId: Long, updateClosure: (MetaAccountLocal) -> MetaAccountLocal) {
|
||||
contract {
|
||||
callsInPlace(updateClosure, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
|
||||
val metaAccount = requireNotNull(getMetaAccount(metaId)) {
|
||||
"Meta account $metaId was not found"
|
||||
}
|
||||
|
||||
val updated = updateClosure(metaAccount)
|
||||
require(updated.id == metaId) {
|
||||
"Cannot modify metaId"
|
||||
}
|
||||
|
||||
updateMetaAccount(updated)
|
||||
}
|
||||
|
||||
class MetaAccountWithBalanceLocal(
|
||||
val id: Long,
|
||||
val freeInPlanks: BigInteger,
|
||||
val reservedInPlanks: BigInteger,
|
||||
val offChainBalance: BigInteger?,
|
||||
val precision: Int,
|
||||
val rate: BigDecimal?
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.MultisigOperationCallLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class MultisigOperationsDao {
|
||||
|
||||
@Query("SELECT * FROM multisig_operation_call")
|
||||
abstract fun observeOperations(): Flow<List<MultisigOperationCallLocal>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertOperation(operation: MultisigOperationCallLocal)
|
||||
|
||||
@Query("DELETE FROM multisig_operation_call WHERE metaId = :metaId AND chainId = :chainId AND callHash NOT IN (:excludedCallHashes)")
|
||||
abstract fun removeOperationsExclude(metaId: Long, chainId: String, excludedCallHashes: List<String>)
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.NftLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class NftDao {
|
||||
|
||||
@Query("SELECT * FROM nfts WHERE metaId = :metaId")
|
||||
abstract fun nftsFlow(metaId: Long): Flow<List<NftLocal>>
|
||||
|
||||
@Query("SELECT * FROM nfts WHERE metaId = :metaId AND type = :type AND chainId = :chainId")
|
||||
abstract suspend fun getNfts(chainId: String, metaId: Long, type: NftLocal.Type): List<NftLocal>
|
||||
|
||||
@Delete
|
||||
protected abstract suspend fun deleteNfts(nfts: List<NftLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun insertNfts(nfts: List<NftLocal>)
|
||||
|
||||
@Update
|
||||
protected abstract suspend fun updateNft(nft: NftLocal)
|
||||
|
||||
@Query("SELECT * FROM nfts WHERE identifier = :nftIdentifier")
|
||||
abstract suspend fun getNft(nftIdentifier: String): NftLocal
|
||||
|
||||
@Query("SELECT type FROM nfts WHERE identifier = :nftIdentifier")
|
||||
abstract suspend fun getNftType(nftIdentifier: String): NftLocal.Type
|
||||
|
||||
@Query("UPDATE nfts SET wholeDetailsLoaded = 1 WHERE identifier = :nftIdentifier")
|
||||
abstract suspend fun markFullSynced(nftIdentifier: String)
|
||||
|
||||
@Transaction
|
||||
open suspend fun insertNftsDiff(
|
||||
nftType: NftLocal.Type,
|
||||
chainId: String,
|
||||
metaId: Long,
|
||||
newNfts: List<NftLocal>,
|
||||
forceOverwrite: Boolean
|
||||
) {
|
||||
val oldNfts = getNfts(chainId, metaId, nftType)
|
||||
|
||||
val diff = CollectionDiffer.findDiff(newNfts, oldNfts, forceUseNewItems = forceOverwrite)
|
||||
|
||||
deleteNfts(diff.removed)
|
||||
insertNfts(diff.newOrUpdated)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open suspend fun updateNft(nftIdentifier: String, update: (NftLocal) -> NftLocal) {
|
||||
val nft = getNft(nftIdentifier)
|
||||
|
||||
val updated = update(nft)
|
||||
|
||||
updateNft(updated)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.NodeLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class NodeDao {
|
||||
|
||||
@Query("select * from nodes")
|
||||
abstract fun nodesFlow(): Flow<List<NodeLocal>>
|
||||
|
||||
@Query("select * from nodes")
|
||||
abstract suspend fun getNodes(): List<NodeLocal>
|
||||
|
||||
@Query("select * from nodes where link = :link")
|
||||
abstract suspend fun getNode(link: String): NodeLocal
|
||||
|
||||
@Query("select * from nodes where id = :id")
|
||||
abstract suspend fun getNodeById(id: Int): NodeLocal
|
||||
|
||||
@Query("select count(*) from nodes where link = :nodeHost")
|
||||
abstract suspend fun getNodesCountByHost(nodeHost: String): Int
|
||||
|
||||
@Query("select exists (select * from nodes where link = :nodeHost)")
|
||||
abstract suspend fun checkNodeExists(nodeHost: String): Boolean
|
||||
|
||||
@Query("DELETE FROM nodes where link = :link")
|
||||
abstract suspend fun remove(link: String)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(nodes: List<NodeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(nodes: NodeLocal): Long
|
||||
|
||||
@Query("update nodes set name = :newName, link = :newHost, networkType = :networkType where id = :id")
|
||||
abstract suspend fun updateNode(id: Int, newName: String, newHost: String, networkType: Int)
|
||||
|
||||
@Query("SELECT * from nodes where isDefault = 1 AND networkType = :networkType")
|
||||
abstract suspend fun getDefaultNodeFor(networkType: Int): NodeLocal
|
||||
|
||||
@Query("select * from nodes limit 1")
|
||||
abstract suspend fun getFirstNode(): NodeLocal
|
||||
|
||||
@Query("delete from nodes where id = :nodeId")
|
||||
abstract suspend fun deleteNode(nodeId: Int)
|
||||
|
||||
@Query("UPDATE nodes SET isActive = 1 WHERE id = :newActiveNodeId")
|
||||
protected abstract suspend fun makeActive(newActiveNodeId: Int)
|
||||
|
||||
@Query("UPDATE nodes SET isActive = 0 WHERE isActive = 1")
|
||||
protected abstract suspend fun inactiveCurrentNode()
|
||||
|
||||
@Query("SELECT * FROM nodes WHERE isActive = 1")
|
||||
abstract fun activeNodeFlow(): Flow<NodeLocal?>
|
||||
|
||||
@Transaction
|
||||
open suspend fun switchActiveNode(newNodeId: Int) {
|
||||
inactiveCurrentNode()
|
||||
|
||||
makeActive(newNodeId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.common.utils.mapNotNullToSet
|
||||
import io.novafoundation.nova.core_db.model.operation.DirectRewardTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.ExtrinsicTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationBaseLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationJoin
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.OperationTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.PoolRewardTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.SwapTypeLocal
|
||||
import io.novafoundation.nova.core_db.model.operation.TransferTypeLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
private const val ID_FILTER = "address = :address AND chainId = :chainId AND assetId = :chainAssetId"
|
||||
|
||||
@Dao
|
||||
abstract class OperationDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertOperationBase(operation: OperationBaseLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertTransferType(type: TransferTypeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertDirectRewardType(type: DirectRewardTypeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertPoolRewardType(type: PoolRewardTypeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertExtrinsicType(type: ExtrinsicTypeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertSwapType(type: SwapTypeLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertOperationsBase(operations: List<OperationBaseLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertTransferTypes(types: List<TransferTypeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertDirectRewardTypes(types: List<DirectRewardTypeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertPoolRewardTypes(types: List<PoolRewardTypeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertExtrinsicTypes(types: List<ExtrinsicTypeLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertSwapTypes(types: List<SwapTypeLocal>)
|
||||
|
||||
@Transaction
|
||||
open suspend fun insert(operation: OperationLocal) {
|
||||
insertOperationBase(operation.base)
|
||||
insertOperationType(operation.type)
|
||||
}
|
||||
|
||||
@Transaction
|
||||
open suspend fun insertAll(operations: List<OperationLocal>) {
|
||||
insertAllInternal(operations)
|
||||
}
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT
|
||||
o.assetId as o_assetId, o.chainId o_chainId, o.id as o_id, o.address as o_address, o.time o_time, o.status as o_status, o.source o_source, o.hash as o_hash,
|
||||
t.amount as t_amount, t.fee as t_fee, t.sender as t_sender, t.receiver as t_receiver,
|
||||
e.contentType as e_contentType, e.module as e_module, e.call as e_call, e.fee as e_fee,
|
||||
rd.isReward as rd_isReward, rd.amount as rd_amount, rd.validator as rd_validator, rd.era as rd_era, rd.eventId as rd_eventId,
|
||||
rp.isReward as rp_isReward, rp.amount as rp_amount, rp.poolId as rp_poolId, rp.eventId as rp_eventId,
|
||||
s.fee_chainId as s_fee_chainId, s.fee_assetId as s_fee_assetId, s.fee_amount as s_fee_amount,
|
||||
s.assetIn_chainId as s_assetIn_chainId, s.assetIn_assetId as s_assetIn_assetId, s.assetIn_amount as s_assetIn_amount,
|
||||
s.assetOut_chainId as s_assetOut_chainId, s.assetOut_assetId as s_assetOut_assetId, s.assetOut_amount as s_assetOut_amount
|
||||
FROM operations as o
|
||||
LEFT JOIN operation_transfers as t ON t.operationId = o.id AND t.assetId = o.assetId AND t.chainId = o.chainId AND t.address = o.address
|
||||
LEFT JOIN operation_extrinsics as e ON e.operationId = o.id AND e.assetId = o.assetId AND e.chainId = o.chainId AND e.address = o.address
|
||||
LEFT JOIN operation_rewards_direct as rd ON rd.operationId = o.id AND rd.assetId = o.assetId AND rd.chainId = o.chainId AND rd.address = o.address
|
||||
LEFT JOIN operation_rewards_pool as rp ON rp.operationId = o.id AND rp.assetId = o.assetId AND rp.chainId = o.chainId AND rp.address = o.address
|
||||
LEFT JOIN operation_swaps as s ON s.operationId = o.id AND s.assetId = o.assetId AND s.chainId = o.chainId AND s.address = o.address
|
||||
WHERE o.address = :address AND o.chainId = :chainId AND o.assetId = :chainAssetId
|
||||
ORDER BY (case when o.status = :statusUp then 0 else 1 end), o.time DESC
|
||||
"""
|
||||
)
|
||||
abstract fun observe(
|
||||
address: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
statusUp: OperationBaseLocal.Status = OperationBaseLocal.Status.PENDING
|
||||
): Flow<List<OperationJoin>>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM operation_transfers
|
||||
WHERE address = :address AND chainId = :chainId AND assetId = :chainAssetId AND operationId = :operationId
|
||||
"""
|
||||
)
|
||||
abstract suspend fun getTransferType(
|
||||
operationId: String,
|
||||
address: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int
|
||||
): TransferTypeLocal?
|
||||
|
||||
@Transaction
|
||||
open suspend fun insertFromRemote(
|
||||
accountAddress: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
operations: List<OperationLocal>
|
||||
) {
|
||||
clearBySource(accountAddress, chainId, chainAssetId, OperationBaseLocal.Source.REMOTE)
|
||||
|
||||
val operationsWithHashes = operations.mapNotNullToSet { it.base.hash }
|
||||
if (operationsWithHashes.isNotEmpty()) {
|
||||
clearByHashes(accountAddress, chainId, chainAssetId, operationsWithHashes)
|
||||
}
|
||||
|
||||
val oldestTime = operations.minOfOrNull { it.base.time }
|
||||
oldestTime?.let {
|
||||
clearOld(accountAddress, chainId, chainAssetId, oldestTime)
|
||||
}
|
||||
|
||||
insertAllInternal(operations)
|
||||
}
|
||||
|
||||
@Query("DELETE FROM operations WHERE $ID_FILTER AND source = :source")
|
||||
protected abstract suspend fun clearBySource(
|
||||
address: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
source: OperationBaseLocal.Source
|
||||
): Int
|
||||
|
||||
@Query("DELETE FROM operations WHERE time < :minTime AND $ID_FILTER")
|
||||
protected abstract suspend fun clearOld(
|
||||
address: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
minTime: Long
|
||||
): Int
|
||||
|
||||
@Query("DELETE FROM operations WHERE $ID_FILTER AND hash in (:hashes)")
|
||||
protected abstract suspend fun clearByHashes(
|
||||
address: String,
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
hashes: Set<String>
|
||||
): Int
|
||||
|
||||
private suspend fun insertOperationType(type: OperationTypeLocal) {
|
||||
when (type) {
|
||||
is ExtrinsicTypeLocal -> insertExtrinsicType(type)
|
||||
is DirectRewardTypeLocal -> insertDirectRewardType(type)
|
||||
is PoolRewardTypeLocal -> insertPoolRewardType(type)
|
||||
is SwapTypeLocal -> insertSwapType(type)
|
||||
is TransferTypeLocal -> insertTransferType(type)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun insertAllInternal(operations: List<OperationLocal>) {
|
||||
insertOperationsBase(operations.map { it.base })
|
||||
insertOperationTypes(operations.map { it.type })
|
||||
}
|
||||
|
||||
private suspend fun insertOperationTypes(types: List<OperationTypeLocal>) {
|
||||
val transfers = types.filterIsInstance<TransferTypeLocal>()
|
||||
val extrinsics = types.filterIsInstance<ExtrinsicTypeLocal>()
|
||||
val directRewards = types.filterIsInstance<DirectRewardTypeLocal>()
|
||||
val poolRewards = types.filterIsInstance<PoolRewardTypeLocal>()
|
||||
val swaps = types.filterIsInstance<SwapTypeLocal>()
|
||||
|
||||
insertTransferTypes(transfers)
|
||||
insertExtrinsicTypes(extrinsics)
|
||||
insertDirectRewardTypes(directRewards)
|
||||
insertPoolRewardTypes(poolRewards)
|
||||
insertSwapTypes(swaps)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.PhishingAddressLocal
|
||||
|
||||
@Dao
|
||||
interface PhishingAddressDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(addresses: List<PhishingAddressLocal>)
|
||||
|
||||
@Query("delete from phishing_addresses")
|
||||
suspend fun clearTable()
|
||||
|
||||
@Query("select publicKey from phishing_addresses")
|
||||
suspend fun getAllAddresses(): List<String>
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.PhishingSiteLocal
|
||||
|
||||
@Dao
|
||||
abstract class PhishingSitesDao {
|
||||
|
||||
@Query("SELECT EXISTS (SELECT * FROM phishing_sites WHERE host in (:hostSuffixes))")
|
||||
abstract suspend fun isPhishing(hostSuffixes: List<String>): Boolean
|
||||
|
||||
@Transaction
|
||||
open suspend fun updatePhishingSites(newSites: List<PhishingSiteLocal>) {
|
||||
clearPhishingSites()
|
||||
|
||||
insertPhishingSites(newSites)
|
||||
}
|
||||
|
||||
@Query("DELETE FROM phishing_sites")
|
||||
protected abstract suspend fun clearPhishingSites()
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
protected abstract suspend fun insertPhishingSites(sites: List<PhishingSiteLocal>)
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.StakingDashboardAccountsView
|
||||
import io.novafoundation.nova.core_db.model.StakingDashboardItemLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface StakingDashboardDao {
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM staking_dashboard_items WHERE
|
||||
metaId = :metaId
|
||||
AND chainId = :chainId
|
||||
AND chainAssetId = :chainAssetId
|
||||
AND stakingType = :stakingType
|
||||
"""
|
||||
)
|
||||
suspend fun getDashboardItem(
|
||||
chainId: String,
|
||||
chainAssetId: Int,
|
||||
stakingType: String,
|
||||
metaId: Long,
|
||||
): StakingDashboardItemLocal?
|
||||
|
||||
@Query("SELECT * FROM staking_dashboard_items WHERE metaId = :metaId")
|
||||
fun dashboardItemsFlow(metaId: Long): Flow<List<StakingDashboardItemLocal>>
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM staking_dashboard_items
|
||||
WHERE metaId = :metaId AND chainId = :chainId AND chainAssetId = :assetId AND stakingType IN (:assetTypes)
|
||||
"""
|
||||
)
|
||||
fun dashboardItemsFlow(metaId: Long, chainId: String, assetId: Int, assetTypes: List<String>): Flow<List<StakingDashboardItemLocal>>
|
||||
|
||||
@Query("SELECT chainId, chainAssetId, stakingType, stakeStatusAccount, rewardsAccount FROM staking_dashboard_items WHERE metaId = :metaId")
|
||||
fun stakingAccountsViewFlow(metaId: Long): Flow<List<StakingDashboardAccountsView>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertItem(dashboardItemLocal: StakingDashboardItemLocal)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.StakingRewardPeriodLocal
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface StakingRewardPeriodDao {
|
||||
|
||||
@Query("SELECT * FROM staking_reward_period WHERE accountId = :accountId AND chainId = :chainId AND assetId = :assetId AND stakingType = :stakingType")
|
||||
suspend fun getStakingRewardPeriod(accountId: AccountId, chainId: String, assetId: Int, stakingType: String): StakingRewardPeriodLocal?
|
||||
|
||||
@Query("SELECT * FROM staking_reward_period WHERE accountId = :accountId AND chainId = :chainId AND assetId = :assetId AND stakingType = :stakingType")
|
||||
fun observeStakingRewardPeriod(accountId: AccountId, chainId: String, assetId: Int, stakingType: String): Flow<StakingRewardPeriodLocal?>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertStakingRewardPeriod(stakingRewardPeriodLocal: StakingRewardPeriodLocal)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.TotalRewardLocal
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
abstract class StakingTotalRewardDao {
|
||||
|
||||
@Query(
|
||||
"""
|
||||
SELECT * FROM total_reward
|
||||
WHERE accountId = :accountId AND chainId = :chainId AND chainAssetId = :chainAssetId and stakingType = :stakingType
|
||||
"""
|
||||
)
|
||||
abstract fun observeTotalRewards(accountId: AccountId, chainId: String, chainAssetId: Int, stakingType: String): Flow<TotalRewardLocal>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(totalRewardLocal: TotalRewardLocal)
|
||||
|
||||
@Query("DELETE FROM total_reward")
|
||||
abstract suspend fun deleteAll()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import io.novafoundation.nova.core_db.model.StorageEntryLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
private const val SELECT_FULL_KEY_QUERY = "SELECT * from storage WHERE chainId = :chainId AND storageKey = :fullKey"
|
||||
private const val SELECT_PREFIX_KEY_QUERY = "SELECT * from storage WHERE chainId = :chainId AND storageKey LIKE :keyPrefix || '%'"
|
||||
|
||||
@Dao
|
||||
abstract class StorageDao {
|
||||
|
||||
@Query("SELECT EXISTS($SELECT_PREFIX_KEY_QUERY)")
|
||||
abstract suspend fun isPrefixInCache(chainId: String, keyPrefix: String): Boolean
|
||||
|
||||
@Query("SELECT EXISTS($SELECT_FULL_KEY_QUERY)")
|
||||
abstract suspend fun isFullKeyInCache(chainId: String, fullKey: String): Boolean
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(entry: StorageEntryLocal)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insert(entries: List<StorageEntryLocal>)
|
||||
|
||||
@Query("DELETE FROM storage WHERE chainId = :chainId AND storageKey LIKE :prefix || '%'")
|
||||
abstract suspend fun removeByPrefix(prefix: String, chainId: String)
|
||||
|
||||
@Query(
|
||||
"""
|
||||
DELETE FROM storage WHERE chainId = :chainId
|
||||
AND storageKey LIKE :prefix || '%'
|
||||
AND storageKey NOT IN (:exceptionFullKeys)
|
||||
"""
|
||||
)
|
||||
abstract suspend fun removeByPrefixExcept(prefix: String, exceptionFullKeys: List<String>, chainId: String)
|
||||
|
||||
@Query(SELECT_FULL_KEY_QUERY)
|
||||
abstract fun observeEntry(chainId: String, fullKey: String): Flow<StorageEntryLocal?>
|
||||
|
||||
@Query(SELECT_PREFIX_KEY_QUERY)
|
||||
abstract fun observeEntries(chainId: String, keyPrefix: String): Flow<List<StorageEntryLocal>>
|
||||
|
||||
@Query("SELECT storageKey from storage WHERE chainId = :chainId AND storageKey LIKE :keyPrefix || '%'")
|
||||
abstract suspend fun getKeys(chainId: String, keyPrefix: String): List<String>
|
||||
|
||||
@Query("SELECT * from storage WHERE chainId = :chainId AND storageKey in (:fullKeys)")
|
||||
abstract fun observeEntries(chainId: String, fullKeys: List<String>): Flow<List<StorageEntryLocal>>
|
||||
|
||||
@Query("SELECT storageKey from storage WHERE chainId = :chainId AND storageKey in (:keys)")
|
||||
abstract suspend fun filterKeysInCache(chainId: String, keys: List<String>): List<String>
|
||||
|
||||
@Transaction
|
||||
open suspend fun insertPrefixedEntries(entries: List<StorageEntryLocal>, prefix: String, chainId: String) {
|
||||
removeByPrefix(prefix, chainId)
|
||||
|
||||
insert(entries)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.TinderGovBasketItemLocal
|
||||
import io.novafoundation.nova.core_db.model.TinderGovVotingPowerLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface TinderGovDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun setVotingPower(item: TinderGovVotingPowerLocal)
|
||||
|
||||
@Query("SELECT * FROM tinder_gov_voting_power WHERE metaId = :metaId AND chainId = :chainId")
|
||||
suspend fun getVotingPower(metaId: Long, chainId: String): TinderGovVotingPowerLocal?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun addToBasket(item: TinderGovBasketItemLocal)
|
||||
|
||||
@Delete
|
||||
suspend fun removeFromBasket(item: TinderGovBasketItemLocal)
|
||||
|
||||
@Delete
|
||||
suspend fun removeFromBasket(items: List<TinderGovBasketItemLocal>)
|
||||
|
||||
@Query("SELECT * FROM tinder_gov_basket WHERE metaId = :metaId AND chainId == :chainId")
|
||||
suspend fun getBasket(metaId: Long, chainId: String): List<TinderGovBasketItemLocal>
|
||||
|
||||
@Query("SELECT * FROM tinder_gov_basket WHERE metaId = :metaId AND chainId == :chainId")
|
||||
fun observeBasket(metaId: Long, chainId: String): Flow<List<TinderGovBasketItemLocal>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM tinder_gov_basket WHERE metaId = :metaId AND chainId == :chainId")
|
||||
fun basketSize(metaId: Long, chainId: String): Int
|
||||
|
||||
@Query("DELETE FROM tinder_gov_basket WHERE metaId = :metaId AND chainId == :chainId")
|
||||
fun clearBasket(metaId: Long, chainId: String)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import io.novafoundation.nova.common.utils.CollectionDiffer
|
||||
import io.novafoundation.nova.core_db.model.TokenLocal
|
||||
import io.novafoundation.nova.core_db.model.TokenWithCurrency
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
private const val RETRIEVE_TOKEN_WITH_CURRENCY = """
|
||||
SELECT * FROM currencies AS currency
|
||||
LEFT OUTER JOIN tokens AS token ON token.currencyId = currency.id AND token.tokenSymbol = :symbol
|
||||
WHERE currency.selected = 1
|
||||
"""
|
||||
|
||||
private const val RETRIEVE_TOKENS_WITH_CURRENCY = """
|
||||
SELECT * FROM currencies AS currency
|
||||
LEFT OUTER JOIN tokens AS token ON token.currencyId = currency.id AND token.tokenSymbol in (:symbols)
|
||||
WHERE currency.selected = 1
|
||||
"""
|
||||
|
||||
private const val INSERT_TOKEN_WITH_SELECTED_CURRENCY = """
|
||||
INSERT OR IGNORE INTO tokens (tokenSymbol, rate, currencyId, recentRateChange)
|
||||
VALUES(:symbol, NULL, (SELECT id FROM currencies WHERE selected = 1), NULL)
|
||||
"""
|
||||
|
||||
@Dao
|
||||
abstract class TokenDao {
|
||||
|
||||
@Transaction
|
||||
open suspend fun applyDiff(diff: CollectionDiffer.Diff<TokenLocal>) {
|
||||
deleteTokens(diff.removed)
|
||||
insertTokens(diff.added)
|
||||
updateTokens(diff.updated)
|
||||
}
|
||||
|
||||
@Query(RETRIEVE_TOKEN_WITH_CURRENCY)
|
||||
abstract suspend fun getTokenWithCurrency(symbol: String): TokenWithCurrency?
|
||||
|
||||
@Query(RETRIEVE_TOKENS_WITH_CURRENCY)
|
||||
abstract fun observeTokensWithCurrency(symbols: List<String>): Flow<List<TokenWithCurrency>>
|
||||
|
||||
@Query(RETRIEVE_TOKENS_WITH_CURRENCY)
|
||||
abstract fun getTokensWithCurrency(symbols: List<String>): List<TokenWithCurrency>
|
||||
|
||||
@Query(RETRIEVE_TOKEN_WITH_CURRENCY)
|
||||
abstract fun observeTokenWithCurrency(symbol: String): Flow<TokenWithCurrency>
|
||||
|
||||
@Query("SELECT * FROM tokens")
|
||||
abstract suspend fun getTokens(): List<TokenLocal>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertTokens(tokens: List<TokenLocal>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
abstract suspend fun insertToken(token: TokenLocal)
|
||||
|
||||
@Query(INSERT_TOKEN_WITH_SELECTED_CURRENCY)
|
||||
abstract suspend fun insertTokenWithSelectedCurrency(symbol: String)
|
||||
|
||||
@Update
|
||||
abstract suspend fun updateTokens(chains: List<TokenLocal>)
|
||||
|
||||
@Delete
|
||||
abstract suspend fun deleteTokens(tokens: List<TokenLocal>)
|
||||
|
||||
@Query("DELETE FROM tokens")
|
||||
abstract suspend fun deleteAll()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.novafoundation.nova.core_db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import io.novafoundation.nova.core_db.model.WalletConnectPairingLocal
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface WalletConnectSessionsDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertPairing(pairing: WalletConnectPairingLocal)
|
||||
|
||||
@Query("DELETE FROM wallet_connect_pairings WHERE pairingTopic = :pairingTopic")
|
||||
suspend fun deletePairing(pairingTopic: String)
|
||||
|
||||
@Query("SELECT * FROM wallet_connect_pairings WHERE pairingTopic = :pairingTopic")
|
||||
suspend fun getPairing(pairingTopic: String): WalletConnectPairingLocal?
|
||||
|
||||
@Query("SELECT * FROM wallet_connect_pairings WHERE pairingTopic = :pairingTopic")
|
||||
fun pairingFlow(pairingTopic: String): Flow<WalletConnectPairingLocal?>
|
||||
|
||||
@Query("DELETE FROM wallet_connect_pairings WHERE pairingTopic NOT IN (:pairingTopics)")
|
||||
suspend fun removeAllPairingsOtherThan(pairingTopics: List<String>)
|
||||
|
||||
@Query("SELECT * FROM wallet_connect_pairings")
|
||||
fun allPairingsFlow(): Flow<List<WalletConnectPairingLocal>>
|
||||
|
||||
@Query("SELECT * FROM wallet_connect_pairings WHERE metaId = :metaId")
|
||||
fun pairingsByMetaIdFlow(metaId: Long): Flow<List<WalletConnectPairingLocal>>
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package io.novafoundation.nova.core_db.di
|
||||
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import io.novafoundation.nova.core_db.dao.AccountDao
|
||||
import io.novafoundation.nova.core_db.dao.AccountStakingDao
|
||||
import io.novafoundation.nova.core_db.dao.AssetDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserHostSettingsDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserTabsDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainAssetDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainDao
|
||||
import io.novafoundation.nova.core_db.dao.CoinPriceDao
|
||||
import io.novafoundation.nova.core_db.dao.ContributionDao
|
||||
import io.novafoundation.nova.core_db.dao.CurrencyDao
|
||||
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
|
||||
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
|
||||
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.GiftsDao
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.HoldsDao
|
||||
import io.novafoundation.nova.core_db.dao.LockDao
|
||||
import io.novafoundation.nova.core_db.dao.MetaAccountDao
|
||||
import io.novafoundation.nova.core_db.dao.MultisigOperationsDao
|
||||
import io.novafoundation.nova.core_db.dao.NftDao
|
||||
import io.novafoundation.nova.core_db.dao.NodeDao
|
||||
import io.novafoundation.nova.core_db.dao.OperationDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingAddressDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingSitesDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingDashboardDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingRewardPeriodDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingTotalRewardDao
|
||||
import io.novafoundation.nova.core_db.dao.StorageDao
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.core_db.dao.TokenDao
|
||||
import io.novafoundation.nova.core_db.dao.WalletConnectSessionsDao
|
||||
|
||||
interface DbApi {
|
||||
|
||||
val phishingSitesDao: PhishingSitesDao
|
||||
|
||||
val favouritesDAppsDao: FavouriteDAppsDao
|
||||
|
||||
val currencyDao: CurrencyDao
|
||||
|
||||
val walletConnectSessionsDao: WalletConnectSessionsDao
|
||||
|
||||
val stakingDashboardDao: StakingDashboardDao
|
||||
|
||||
val externalBalanceDao: ExternalBalanceDao
|
||||
|
||||
val holdsDao: HoldsDao
|
||||
|
||||
fun provideDatabase(): AppDatabase
|
||||
|
||||
fun provideLockDao(): LockDao
|
||||
|
||||
fun provideAccountDao(): AccountDao
|
||||
|
||||
fun contributionDao(): ContributionDao
|
||||
|
||||
fun provideNodeDao(): NodeDao
|
||||
|
||||
fun provideAssetDao(): AssetDao
|
||||
|
||||
fun provideOperationDao(): OperationDao
|
||||
|
||||
fun providePhishingAddressDao(): PhishingAddressDao
|
||||
|
||||
fun storageDao(): StorageDao
|
||||
|
||||
fun tokenDao(): TokenDao
|
||||
|
||||
fun accountStakingDao(): AccountStakingDao
|
||||
|
||||
fun stakingTotalRewardDao(): StakingTotalRewardDao
|
||||
|
||||
fun chainDao(): ChainDao
|
||||
|
||||
fun chainAssetDao(): ChainAssetDao
|
||||
|
||||
fun metaAccountDao(): MetaAccountDao
|
||||
|
||||
fun dappAuthorizationDao(): DappAuthorizationDao
|
||||
|
||||
fun nftDao(): NftDao
|
||||
|
||||
fun governanceDAppsDao(): GovernanceDAppsDao
|
||||
|
||||
fun browserHostSettingsDao(): BrowserHostSettingsDao
|
||||
|
||||
fun coinPriceDao(): CoinPriceDao
|
||||
|
||||
fun stakingRewardPeriodDao(): StakingRewardPeriodDao
|
||||
|
||||
fun tinderGovDao(): TinderGovDao
|
||||
|
||||
fun browserTabsDao(): BrowserTabsDao
|
||||
|
||||
fun multisigOperationsDao(): MultisigOperationsDao
|
||||
|
||||
fun giftsDao(): GiftsDao
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.di
|
||||
|
||||
import dagger.Component
|
||||
import io.novafoundation.nova.common.di.CommonApi
|
||||
import io.novafoundation.nova.common.di.scope.ApplicationScope
|
||||
|
||||
@Component(
|
||||
modules = [
|
||||
DbModule::class
|
||||
],
|
||||
dependencies = [
|
||||
DbDependencies::class
|
||||
]
|
||||
)
|
||||
@ApplicationScope
|
||||
abstract class DbComponent : DbApi {
|
||||
|
||||
@Component(
|
||||
dependencies = [
|
||||
CommonApi::class
|
||||
]
|
||||
)
|
||||
interface DbDependenciesComponent : DbDependencies
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.novafoundation.nova.core_db.di
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.Gson
|
||||
import io.novafoundation.nova.common.data.secrets.v1.SecretStoreV1
|
||||
import io.novafoundation.nova.common.data.secrets.v2.SecretStoreV2
|
||||
import io.novafoundation.nova.common.data.storage.Preferences
|
||||
|
||||
interface DbDependencies {
|
||||
|
||||
fun gson(): Gson
|
||||
|
||||
fun preferences(): Preferences
|
||||
|
||||
fun context(): Context
|
||||
|
||||
fun secretStoreV1(): SecretStoreV1
|
||||
|
||||
fun secretStoreV2(): SecretStoreV2
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.novafoundation.nova.core_db.di
|
||||
|
||||
import io.novafoundation.nova.common.di.FeatureApiHolder
|
||||
import io.novafoundation.nova.common.di.FeatureContainer
|
||||
import io.novafoundation.nova.common.di.scope.ApplicationScope
|
||||
import javax.inject.Inject
|
||||
|
||||
@ApplicationScope
|
||||
class DbHolder @Inject constructor(
|
||||
featureContainer: FeatureContainer
|
||||
) : FeatureApiHolder(featureContainer) {
|
||||
|
||||
override fun initializeDependencies(): Any {
|
||||
val dbDependencies = DaggerDbComponent_DbDependenciesComponent.builder()
|
||||
.commonApi(commonApi())
|
||||
.build()
|
||||
return DaggerDbComponent.builder()
|
||||
.dbDependencies(dbDependencies)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package io.novafoundation.nova.core_db.di
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.di.scope.ApplicationScope
|
||||
import io.novafoundation.nova.core_db.AppDatabase
|
||||
import io.novafoundation.nova.core_db.dao.AccountDao
|
||||
import io.novafoundation.nova.core_db.dao.AccountStakingDao
|
||||
import io.novafoundation.nova.core_db.dao.AssetDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserHostSettingsDao
|
||||
import io.novafoundation.nova.core_db.dao.BrowserTabsDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainAssetDao
|
||||
import io.novafoundation.nova.core_db.dao.ChainDao
|
||||
import io.novafoundation.nova.core_db.dao.CoinPriceDao
|
||||
import io.novafoundation.nova.core_db.dao.ContributionDao
|
||||
import io.novafoundation.nova.core_db.dao.CurrencyDao
|
||||
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
|
||||
import io.novafoundation.nova.core_db.dao.ExternalBalanceDao
|
||||
import io.novafoundation.nova.core_db.dao.FavouriteDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.GiftsDao
|
||||
import io.novafoundation.nova.core_db.dao.GovernanceDAppsDao
|
||||
import io.novafoundation.nova.core_db.dao.HoldsDao
|
||||
import io.novafoundation.nova.core_db.dao.LockDao
|
||||
import io.novafoundation.nova.core_db.dao.MetaAccountDao
|
||||
import io.novafoundation.nova.core_db.dao.MultisigOperationsDao
|
||||
import io.novafoundation.nova.core_db.dao.NftDao
|
||||
import io.novafoundation.nova.core_db.dao.NodeDao
|
||||
import io.novafoundation.nova.core_db.dao.OperationDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingAddressDao
|
||||
import io.novafoundation.nova.core_db.dao.PhishingSitesDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingDashboardDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingRewardPeriodDao
|
||||
import io.novafoundation.nova.core_db.dao.StakingTotalRewardDao
|
||||
import io.novafoundation.nova.core_db.dao.StorageDao
|
||||
import io.novafoundation.nova.core_db.dao.TinderGovDao
|
||||
import io.novafoundation.nova.core_db.dao.TokenDao
|
||||
import io.novafoundation.nova.core_db.dao.WalletConnectSessionsDao
|
||||
|
||||
@Module
|
||||
class DbModule {
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideAppDatabase(
|
||||
context: Context
|
||||
): AppDatabase {
|
||||
return AppDatabase.get(context)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideUserDao(appDatabase: AppDatabase): AccountDao {
|
||||
return appDatabase.userDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideNodeDao(appDatabase: AppDatabase): NodeDao {
|
||||
return appDatabase.nodeDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideAssetDao(appDatabase: AppDatabase): AssetDao {
|
||||
return appDatabase.assetDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideLockDao(appDatabase: AppDatabase): LockDao {
|
||||
return appDatabase.lockDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideContributionDao(appDatabase: AppDatabase): ContributionDao {
|
||||
return appDatabase.contributionDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideOperationHistoryDao(appDatabase: AppDatabase): OperationDao {
|
||||
return appDatabase.operationDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun providePhishingAddressDao(appDatabase: AppDatabase): PhishingAddressDao {
|
||||
return appDatabase.phishingAddressesDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideStorageDao(appDatabase: AppDatabase): StorageDao {
|
||||
return appDatabase.storageDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideTokenDao(appDatabase: AppDatabase): TokenDao {
|
||||
return appDatabase.tokenDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideAccountStakingDao(appDatabase: AppDatabase): AccountStakingDao {
|
||||
return appDatabase.accountStakingDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideStakingTotalRewardDao(appDatabase: AppDatabase): StakingTotalRewardDao {
|
||||
return appDatabase.stakingTotalRewardDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideChainDao(appDatabase: AppDatabase): ChainDao {
|
||||
return appDatabase.chainDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideChainAssetDao(appDatabase: AppDatabase): ChainAssetDao {
|
||||
return appDatabase.chainAssetDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideMetaAccountDao(appDatabase: AppDatabase): MetaAccountDao {
|
||||
return appDatabase.metaAccountDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideDappAuthorizationDao(appDatabase: AppDatabase): DappAuthorizationDao {
|
||||
return appDatabase.dAppAuthorizationDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideNftDao(appDatabase: AppDatabase): NftDao {
|
||||
return appDatabase.nftDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun providePhishingSitesDao(appDatabase: AppDatabase): PhishingSitesDao {
|
||||
return appDatabase.phishingSitesDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideFavouriteDappsDao(appDatabase: AppDatabase): FavouriteDAppsDao {
|
||||
return appDatabase.favouriteDAppsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideCurrencyDao(appDatabase: AppDatabase): CurrencyDao {
|
||||
return appDatabase.currencyDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideGovernanceDAppDao(appDatabase: AppDatabase): GovernanceDAppsDao {
|
||||
return appDatabase.governanceDAppsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideBrowserHostSettingsDao(appDatabase: AppDatabase): BrowserHostSettingsDao {
|
||||
return appDatabase.browserHostSettingsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideWalletConnectSessionsDao(appDatabase: AppDatabase): WalletConnectSessionsDao {
|
||||
return appDatabase.walletConnectSessionsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideStakingDashboardDao(appDatabase: AppDatabase): StakingDashboardDao {
|
||||
return appDatabase.stakingDashboardDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideCoinPriceDao(appDatabase: AppDatabase): CoinPriceDao {
|
||||
return appDatabase.coinPriceDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideStakingRewardPeriodDao(appDatabase: AppDatabase): StakingRewardPeriodDao {
|
||||
return appDatabase.stakingRewardPeriodDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideExternalBalanceDao(appDatabase: AppDatabase): ExternalBalanceDao {
|
||||
return appDatabase.externalBalanceDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideHoldsDao(appDatabase: AppDatabase): HoldsDao {
|
||||
return appDatabase.holdsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideTinderGovDao(appDatabase: AppDatabase): TinderGovDao {
|
||||
return appDatabase.tinderGovDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideBrowserTabsDao(appDatabase: AppDatabase): BrowserTabsDao {
|
||||
return appDatabase.browserTabsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideMultisigOperationsDao(appDatabase: AppDatabase): MultisigOperationsDao {
|
||||
return appDatabase.multisigOperationsDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ApplicationScope
|
||||
fun provideGiftsDao(appDatabase: AppDatabase): GiftsDao {
|
||||
return appDatabase.giftsDao()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package io.novafoundation.nova.core_db.ext
|
||||
|
||||
import io.novafoundation.nova.core_db.dao.FullAssetIdLocal
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
|
||||
fun ChainAssetLocal.fullId(): FullAssetIdLocal {
|
||||
return FullAssetIdLocal(this.chainId, this.id)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val ChangeDAppAuthorization_10_11 = object : Migration(10, 11) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE dapp_authorizations")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `dapp_authorizations` (
|
||||
`baseUrl` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`dAppTitle` TEXT, `authorized` INTEGER,
|
||||
PRIMARY KEY(`baseUrl`, `metaId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val RemoveChainForeignKeyFromChainAccount_11_12 = object : Migration(11, 12) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_chainId`")
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_metaId`")
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_accountId`")
|
||||
database.execSQL("ALTER TABLE chain_accounts RENAME TO chain_accounts_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_accounts` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`publicKey` BLOB NOT NULL,
|
||||
`accountId` BLOB NOT NULL,
|
||||
`cryptoType` TEXT NOT NULL,
|
||||
PRIMARY KEY(`metaId`, `chainId`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_chainId` ON `chain_accounts` (`chainId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_metaId` ON `chain_accounts` (`metaId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_accountId` ON `chain_accounts` (`accountId`)")
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_accounts
|
||||
SELECT *
|
||||
FROM chain_accounts_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE chain_accounts_old")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
// used on master for Astar hotfix
|
||||
val AddAdditionalFieldToChains_12_13 = object : Migration(12, 13) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN additional TEXT DEFAULT null")
|
||||
}
|
||||
}
|
||||
|
||||
// used on develop for parachainStaking rewards
|
||||
val AddChainToTotalRewards_12_13 = object : Migration(12, 13) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE total_reward")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `total_reward` (
|
||||
`accountAddress` TEXT NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`chainAssetId` INTEGER NOT NULL,
|
||||
`totalReward` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`, `chainAssetId`, `accountAddress`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val FixMigrationConflicts_13_14 = object : Migration(13, 14) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
if (isMigratingFromMaster(database)) {
|
||||
// migrating from master -> execute missing develop migration
|
||||
AddChainToTotalRewards_12_13.migrate(database)
|
||||
} else {
|
||||
// migrating from develop -> execute missing master migration
|
||||
AddAdditionalFieldToChains_12_13.migrate(database)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isMigratingFromMaster(database: SupportSQLiteDatabase): Boolean {
|
||||
return runCatching {
|
||||
// check for column added in astar hotfix (master)
|
||||
database.query("SELECT additional FROM chains LIMIT 1")
|
||||
}.fold(
|
||||
onSuccess = { true },
|
||||
onFailure = { false }
|
||||
)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.converters.MetaAccountTypeConverters
|
||||
import io.novafoundation.nova.core_db.model.chain.account.MetaAccountLocal
|
||||
|
||||
val AddMetaAccountType_14_15 = object : Migration(14, 15) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
val converters = MetaAccountTypeConverters()
|
||||
|
||||
// all accounts that exist till now are added via secrets
|
||||
val defaultType = MetaAccountLocal.Type.SECRETS
|
||||
val typeRepresentationInDb = converters.fromEnum(defaultType)
|
||||
|
||||
database.execSQL("ALTER TABLE meta_accounts ADD COLUMN type TEXT NOT NULL DEFAULT '$typeRepresentationInDb'")
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val NullableSubstratePublicKey_15_16 = object : Migration(15, 16) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("DROP INDEX `index_meta_accounts_substrateAccountId`")
|
||||
database.execSQL("DROP INDEX `index_meta_accounts_ethereumAddress`")
|
||||
database.execSQL("ALTER TABLE meta_accounts RENAME TO meta_accounts_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `meta_accounts` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`substratePublicKey` BLOB,
|
||||
`substrateCryptoType` TEXT,
|
||||
`substrateAccountId` BLOB NOT NULL,
|
||||
`ethereumPublicKey` BLOB,
|
||||
`ethereumAddress` BLOB,
|
||||
`name` TEXT NOT NULL,
|
||||
`isSelected` INTEGER NOT NULL,
|
||||
`position` INTEGER NOT NULL,
|
||||
`type` TEXT NOT NULL
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_meta_accounts_substrateAccountId` ON `meta_accounts` (`substrateAccountId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_meta_accounts_ethereumAddress` ON `meta_accounts` (`ethereumAddress`)")
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO meta_accounts
|
||||
SELECT *
|
||||
FROM meta_accounts_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE meta_accounts_old")
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val WatchOnlyChainAccounts_16_17 = object : Migration(16, 17) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_chainId`")
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_metaId`")
|
||||
database.execSQL("DROP INDEX `index_chain_accounts_accountId`")
|
||||
database.execSQL("ALTER TABLE chain_accounts RENAME TO chain_accounts_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_accounts` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`publicKey` BLOB,
|
||||
`accountId` BLOB NOT NULL,
|
||||
`cryptoType` TEXT,
|
||||
PRIMARY KEY(`metaId`, `chainId`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_chainId` ON `chain_accounts` (`chainId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_metaId` ON `chain_accounts` (`metaId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_accountId` ON `chain_accounts` (`accountId`)")
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_accounts
|
||||
SELECT *
|
||||
FROM chain_accounts_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE chain_accounts_old")
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val RemoveColorFromChains_17_18 = object : Migration(17, 18) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("ALTER TABLE chains RENAME TO chains_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chains` (
|
||||
`id` TEXT NOT NULL,
|
||||
`parentId` TEXT,
|
||||
`name` TEXT NOT NULL,
|
||||
`icon` TEXT NOT NULL,
|
||||
`prefix` INTEGER NOT NULL,
|
||||
`isEthereumBased` INTEGER NOT NULL,
|
||||
`isTestNet` INTEGER NOT NULL,
|
||||
`hasCrowdloans` INTEGER NOT NULL,
|
||||
`additional` TEXT,
|
||||
`url` TEXT,
|
||||
`overridesCommon` INTEGER,
|
||||
`staking_url` TEXT,
|
||||
`staking_type` TEXT,
|
||||
`history_url` TEXT,
|
||||
`history_type` TEXT,
|
||||
`crowdloans_url` TEXT,
|
||||
`crowdloans_type` TEXT,
|
||||
PRIMARY KEY(`id`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
// select all but color
|
||||
"""
|
||||
INSERT INTO chains
|
||||
SELECT id, parentId, name, icon, prefix, isEthereumBased, isTestNet, hasCrowdloans, additional, url, overridesCommon,
|
||||
staking_url, staking_type, history_url, history_type, crowdloans_url, crowdloans_type
|
||||
FROM chains_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE chains_old")
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddCurrencies_18_19 = object : Migration(18, 19) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `currencies` (
|
||||
`code` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`symbol` TEXT,
|
||||
`category` TEXT NOT NULL,
|
||||
`popular` INTEGER NOT NULL,
|
||||
`id` INTEGER NOT NULL,
|
||||
`coingeckoId` TEXT NOT NULL,
|
||||
`selected` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`id`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val ChangeTokens_19_20 = object : Migration(19, 20) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename table
|
||||
database.execSQL("ALTER TABLE tokens RENAME TO tokens_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `tokens` (
|
||||
`tokenSymbol` TEXT NOT NULL,
|
||||
`rate` TEXT,
|
||||
`recentRateChange` TEXT,
|
||||
`currencyId` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`tokenSymbol`, `currencyId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO tokens (tokenSymbol, rate, recentRateChange, currencyId)
|
||||
SELECT symbol, dollarRate, recentRateChange, 0
|
||||
FROM tokens_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE tokens_old")
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddDAppAuthorizations_1_2 = object : Migration(1, 2) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `dapp_authorizations` (
|
||||
`baseUrl` TEXT NOT NULL,
|
||||
`authorized` INTEGER,
|
||||
PRIMARY KEY(`baseUrl`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val ChangeChainNodes_20_21 = object : Migration(20, 21) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chain_nodes ADD `orderId` INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val NullableSubstrateAccountId_21_22 = object : Migration(21, 22) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("DROP INDEX `index_meta_accounts_substrateAccountId`")
|
||||
database.execSQL("DROP INDEX `index_meta_accounts_ethereumAddress`")
|
||||
database.execSQL("ALTER TABLE meta_accounts RENAME TO meta_accounts_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `meta_accounts` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`substratePublicKey` BLOB,
|
||||
`substrateCryptoType` TEXT,
|
||||
`substrateAccountId` BLOB,
|
||||
`ethereumPublicKey` BLOB,
|
||||
`ethereumAddress` BLOB,
|
||||
`name` TEXT NOT NULL,
|
||||
`isSelected` INTEGER NOT NULL,
|
||||
`position` INTEGER NOT NULL,
|
||||
`type` TEXT NOT NULL
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_meta_accounts_substrateAccountId` ON `meta_accounts` (`substrateAccountId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_meta_accounts_ethereumAddress` ON `meta_accounts` (`ethereumAddress`)")
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO meta_accounts
|
||||
SELECT *
|
||||
FROM meta_accounts_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE meta_accounts_old")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddLocks_22_23 = object : Migration(22, 23) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `locks` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`type` TEXT NOT NULL,
|
||||
`amount` TEXT NOT NULL,
|
||||
PRIMARY KEY(`metaId`, `chainId`, `assetId`, `type`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ,
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ,
|
||||
FOREIGN KEY(`assetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddContributions_23_24 = object : Migration(23, 24) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `contributions` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`paraId` TEXT NOT NULL,
|
||||
`amountInPlanks` TEXT NOT NULL,
|
||||
`sourceId` TEXT NOT NULL,
|
||||
PRIMARY KEY(`metaId`, `chainId`, `assetId`, `paraId`, `sourceId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddGovernanceFlagToChains_24_25 = object : Migration(24, 25) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN hasGovernance INTEGER NOT NULL DEFAULT 0")
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddGovernanceDapps_25_26 = object : Migration(25, 26) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `governance_dapps` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`referendumUrl` TEXT NOT NULL,
|
||||
`iconUrl` TEXT NOT NULL,
|
||||
`details` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`, `name`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val GovernanceFlagToEnum_26_27 = object : Migration(26, 27) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("ALTER TABLE chains RENAME TO chains_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chains` (
|
||||
`id` TEXT NOT NULL,
|
||||
`parentId` TEXT,
|
||||
`name` TEXT NOT NULL,
|
||||
`icon` TEXT NOT NULL,
|
||||
`prefix` INTEGER NOT NULL,
|
||||
`isEthereumBased` INTEGER NOT NULL,
|
||||
`isTestNet` INTEGER NOT NULL,
|
||||
`hasCrowdloans` INTEGER NOT NULL,
|
||||
`governance` TEXT NOT NULL,
|
||||
`additional` TEXT,
|
||||
`url` TEXT,
|
||||
`overridesCommon` INTEGER,
|
||||
`staking_url` TEXT,
|
||||
`staking_type` TEXT,
|
||||
`history_url` TEXT,
|
||||
`history_type` TEXT,
|
||||
`crowdloans_url` TEXT,
|
||||
`crowdloans_type` TEXT,
|
||||
PRIMARY KEY(`id`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val governanceDefault = "NONE"
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
// select all but color
|
||||
"""
|
||||
INSERT INTO chains
|
||||
SELECT id, parentId, name, icon, prefix, isEthereumBased, isTestNet, hasCrowdloans, "$governanceDefault", additional, url, overridesCommon,
|
||||
staking_url, staking_type, history_url, history_type, crowdloans_url, crowdloans_type
|
||||
FROM chains_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE chains_old")
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddGovernanceExternalApiToChain_27_28 = object : Migration(27, 28) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// new columns
|
||||
database.execSQL("ALTER TABLE `chains` ADD COLUMN `governance_url` TEXT")
|
||||
database.execSQL("ALTER TABLE `chains` ADD COLUMN `governance_type` TEXT")
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
|
||||
val AddSourceToLocalAsset_28_29 = object : Migration(28, 29) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE `chain_assets` ADD COLUMN `source` TEXT NOT NULL DEFAULT '${ChainAssetLocal.SOURCE_DEFAULT}'")
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddTransferApisTable_29_30 = object : Migration(29, 30) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
removeTransferApiFieldsFromChains(database)
|
||||
|
||||
addTransferApiTable(database)
|
||||
|
||||
clearOperationsCache(database)
|
||||
}
|
||||
|
||||
private fun clearOperationsCache(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DELETE FROM operations")
|
||||
}
|
||||
|
||||
private fun addTransferApiTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_transfer_history_apis` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetType` TEXT NOT NULL,
|
||||
`apiType` TEXT NOT NULL,
|
||||
`url` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`, `url`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE INDEX IF NOT EXISTS `index_chain_transfer_history_apis_chainId` ON `chain_transfer_history_apis` (`chainId`)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
private fun removeTransferApiFieldsFromChains(database: SupportSQLiteDatabase) {
|
||||
// rename
|
||||
database.execSQL("ALTER TABLE chains RENAME TO chains_old")
|
||||
|
||||
// new table
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chains` (
|
||||
`id` TEXT NOT NULL,
|
||||
`parentId` TEXT,
|
||||
`name` TEXT NOT NULL,
|
||||
`icon` TEXT NOT NULL,
|
||||
`prefix` INTEGER NOT NULL,
|
||||
`isEthereumBased` INTEGER NOT NULL,
|
||||
`isTestNet` INTEGER NOT NULL,
|
||||
`hasCrowdloans` INTEGER NOT NULL,
|
||||
`governance` TEXT NOT NULL,
|
||||
`additional` TEXT,
|
||||
`url` TEXT,
|
||||
`overridesCommon` INTEGER,
|
||||
`staking_url` TEXT,
|
||||
`staking_type` TEXT,
|
||||
`crowdloans_url` TEXT,
|
||||
`crowdloans_type` TEXT,
|
||||
`governance_url` TEXT,
|
||||
`governance_type` TEXT,
|
||||
PRIMARY KEY(`id`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// insert to new from old
|
||||
database.execSQL(
|
||||
// select all but color
|
||||
"""
|
||||
INSERT INTO chains
|
||||
SELECT id, parentId, name, icon, prefix, isEthereumBased, isTestNet, hasCrowdloans, governance,
|
||||
additional, url, overridesCommon, staking_url, staking_type, crowdloans_url, crowdloans_type, governance_url, governance_type
|
||||
FROM chains_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
// delete old
|
||||
database.execSQL("DROP TABLE chains_old")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AssetTypes_2_3 = object : Migration(2, 3) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chain_assets ADD COLUMN type TEXT DEFAULT NULL")
|
||||
database.execSQL("ALTER TABLE chain_assets ADD COLUMN typeExtras TEXT DEFAULT NULL")
|
||||
database.execSQL("ALTER TABLE chain_assets ADD COLUMN icon TEXT DEFAULT NULL")
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
|
||||
val AddEnabledColumnToChainAssets_30_31 = object : Migration(30, 31) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE `chain_assets` ADD COLUMN `enabled` INTEGER NOT NULL DEFAULT ${ChainAssetLocal.ENABLED_DEFAULT_STR}")
|
||||
}
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainAssetLocal
|
||||
|
||||
/**
|
||||
* Due to previous migration of chain & meta account tables by means of rename-create-insert-delete strategy
|
||||
* foreign keys to these tables got renamed and now points to wrong table which causes crashes for subset of users
|
||||
* This migration recreates all affected tables
|
||||
*/
|
||||
val FixBrokenForeignKeys_31_32 = object : Migration(31, 32) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
// foreign key to ChainLocal
|
||||
recreateChainAssets(database)
|
||||
|
||||
// foreign key to ChainAssetLocal which was recreated above
|
||||
recreateAssets(database)
|
||||
|
||||
// foreign key to MetaAccountLocal
|
||||
recreateChainAccount(database)
|
||||
|
||||
// foreign key to ChainLocal
|
||||
recreateChainRuntimeInfo(database)
|
||||
|
||||
// foreign key to ChainLocal
|
||||
recreateChainExplorers(database)
|
||||
|
||||
// foreign key to ChainLocal
|
||||
recreateChainNodes(database)
|
||||
|
||||
// foreign key to ChainLocal, ChainAssetLocal, MetaAccount
|
||||
recreateBalanceLocks(database)
|
||||
}
|
||||
|
||||
private fun recreateChainAssets(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_assets_chainId`")
|
||||
|
||||
database.execSQL("ALTER TABLE chain_assets RENAME TO chain_assets_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_assets` (
|
||||
`id` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`symbol` TEXT NOT NULL,
|
||||
`priceId` TEXT,
|
||||
`staking` TEXT NOT NULL,
|
||||
`precision` INTEGER NOT NULL,
|
||||
`icon` TEXT,
|
||||
`type` TEXT,
|
||||
`source` TEXT NOT NULL DEFAULT '${ChainAssetLocal.SOURCE_DEFAULT}',
|
||||
`buyProviders` TEXT,
|
||||
`typeExtras` TEXT,
|
||||
`enabled` INTEGER NOT NULL DEFAULT ${ChainAssetLocal.ENABLED_DEFAULT_STR},
|
||||
PRIMARY KEY(`chainId`,`id`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_assets
|
||||
SELECT
|
||||
id, chainId, name, symbol, priceId,
|
||||
staking, precision, icon, type, source,
|
||||
buyProviders, typeExtras, enabled
|
||||
FROM chain_assets_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_assets_chainId` ON `chain_assets` (`chainId`)")
|
||||
|
||||
database.execSQL("DROP TABLE chain_assets_old")
|
||||
}
|
||||
|
||||
private fun recreateAssets(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_assets_metaId`")
|
||||
database.execSQL("ALTER TABLE assets RENAME TO assets_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `assets` (
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`freeInPlanks` TEXT NOT NULL,
|
||||
`frozenInPlanks` TEXT NOT NULL,
|
||||
`reservedInPlanks` TEXT NOT NULL,
|
||||
`bondedInPlanks` TEXT NOT NULL,
|
||||
`redeemableInPlanks` TEXT NOT NULL,
|
||||
`unbondingInPlanks` TEXT NOT NULL,
|
||||
PRIMARY KEY(`assetId`,`chainId`,`metaId`),
|
||||
FOREIGN KEY(`assetId`,`chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO assets
|
||||
SELECT
|
||||
assetId, chainId, metaId,
|
||||
freeInPlanks, frozenInPlanks, reservedInPlanks,
|
||||
bondedInPlanks, redeemableInPlanks, unbondingInPlanks
|
||||
FROM assets_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_assets_metaId` ON `assets` (`metaId`)")
|
||||
|
||||
database.execSQL("DROP TABLE assets_old")
|
||||
}
|
||||
|
||||
private fun recreateChainAccount(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_accounts_chainId`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_accounts_metaId`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_accounts_accountId`")
|
||||
|
||||
database.execSQL("ALTER TABLE chain_accounts RENAME TO chain_accounts_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_accounts` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`publicKey` BLOB,
|
||||
`accountId` BLOB NOT NULL,
|
||||
`cryptoType` TEXT,
|
||||
PRIMARY KEY(`metaId`, `chainId`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_accounts
|
||||
SELECT metaId, chainId, publicKey, accountId, cryptoType
|
||||
FROM chain_accounts_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_chainId` ON `chain_accounts` (`chainId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_metaId` ON `chain_accounts` (`metaId`)")
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_accounts_accountId` ON `chain_accounts` (`accountId`)")
|
||||
|
||||
database.execSQL("DROP TABLE chain_accounts_old")
|
||||
}
|
||||
|
||||
private fun recreateChainRuntimeInfo(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_runtimes_chainId`")
|
||||
|
||||
database.execSQL("ALTER TABLE chain_runtimes RENAME TO chain_runtimes_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_runtimes` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`syncedVersion` INTEGER NOT NULL,
|
||||
`remoteVersion` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`chainId`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_runtimes
|
||||
SELECT chainId, syncedVersion, remoteVersion FROM chain_runtimes_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_runtimes_chainId` ON `chain_runtimes` (`chainId`)")
|
||||
|
||||
database.execSQL("DROP TABLE chain_runtimes_old")
|
||||
}
|
||||
|
||||
private fun recreateChainExplorers(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_explorers_chainId`")
|
||||
|
||||
database.execSQL("ALTER TABLE chain_explorers RENAME TO chain_explorers_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_explorers` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`extrinsic` TEXT,
|
||||
`account` TEXT,
|
||||
`event` TEXT,
|
||||
PRIMARY KEY(`chainId`, `name`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_explorers
|
||||
SELECT chainId, name, extrinsic, account, event FROM chain_explorers_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_explorers_chainId` ON `chain_explorers` (`chainId`)")
|
||||
|
||||
database.execSQL("DROP TABLE chain_explorers_old")
|
||||
}
|
||||
|
||||
private fun recreateChainNodes(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_chain_nodes_chainId`")
|
||||
|
||||
database.execSQL("ALTER TABLE chain_nodes RENAME TO chain_nodes_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_nodes` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`url` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`orderId` INTEGER NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(`chainId`, `url`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chain_nodes
|
||||
SELECT chainId, url, name, orderId FROM chain_nodes_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_nodes_chainId` ON `chain_nodes` (`chainId`)")
|
||||
|
||||
database.execSQL("DROP TABLE chain_nodes_old")
|
||||
}
|
||||
|
||||
private fun recreateBalanceLocks(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE locks RENAME TO locks_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `locks` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`type` TEXT NOT NULL,
|
||||
`amount` TEXT NOT NULL,
|
||||
PRIMARY KEY(`metaId`, `chainId`, `assetId`, `type`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE ,
|
||||
FOREIGN KEY(`assetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO locks
|
||||
SELECT metaId, chainId, assetId, type, amount FROM locks_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("DROP TABLE locks_old")
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddVersioningToGovernanceDapps_32_33 = object : Migration(32, 33) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE `governance_dapps`")
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `governance_dapps` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`name` TEXT NOT NULL,
|
||||
`referendumUrlV1` TEXT,
|
||||
`referendumUrlV2` TEXT,
|
||||
`iconUrl` TEXT NOT NULL,
|
||||
`details` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`, `name`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddGovernanceNetworkToExternalApi_33_34 = object : Migration(33, 34) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN `governance_parameters` TEXT")
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddBrowserHostSettings_34_35 = object : Migration(34, 35) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `browser_host_settings` (
|
||||
`hostUrl` TEXT NOT NULL,
|
||||
`isDesktopModeEnabled` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`hostUrl`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val ExtractExternalApiToSeparateTable_35_36 = object : Migration(35, 36) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
removeExternalApisColumnsFromChains(database)
|
||||
|
||||
migrateExternalApisTable(database)
|
||||
|
||||
// recreating chainId causes broken foreign keys to appear on some devices
|
||||
// so we run this migration again to fix it
|
||||
FixBrokenForeignKeys_31_32.migrate(database)
|
||||
}
|
||||
|
||||
private fun migrateExternalApisTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE chain_transfer_history_apis")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chain_external_apis` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`sourceType` TEXT NOT NULL,
|
||||
`apiType` TEXT NOT NULL,
|
||||
`parameters` TEXT,
|
||||
`url` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`, `url`, `apiType`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_chain_external_apis_chainId` ON `chain_external_apis` (`chainId`)")
|
||||
}
|
||||
|
||||
private fun removeExternalApisColumnsFromChains(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chains RENAME TO chains_old")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `chains` (
|
||||
`id` TEXT NOT NULL,
|
||||
`parentId` TEXT,
|
||||
`name` TEXT NOT NULL,
|
||||
`icon` TEXT NOT NULL,
|
||||
`prefix` INTEGER NOT NULL,
|
||||
`isEthereumBased` INTEGER NOT NULL,
|
||||
`isTestNet` INTEGER NOT NULL,
|
||||
`hasCrowdloans` INTEGER NOT NULL,
|
||||
`governance` TEXT NOT NULL,
|
||||
`additional` TEXT,
|
||||
`url` TEXT,
|
||||
`overridesCommon` INTEGER,
|
||||
PRIMARY KEY(`id`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
INSERT INTO chains
|
||||
SELECT
|
||||
id, parentId, name, icon, prefix,
|
||||
isEthereumBased, isTestNet, hasCrowdloans, governance, additional,
|
||||
url, overridesCommon
|
||||
FROM chains_old
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("DROP TABLE chains_old")
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal
|
||||
|
||||
val AddRuntimeFlagToChains_36_37 = object : Migration(36, 37) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
val default = ChainLocal.Default.HAS_SUBSTRATE_RUNTIME
|
||||
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN `hasSubstrateRuntime` INTEGER NOT NULL DEFAULT $default")
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddExtrinsicContentField_37_38 = object : Migration(37, 38) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE operations")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `operations` (
|
||||
`id` TEXT NOT NULL,
|
||||
`address` TEXT NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`chainAssetId` INTEGER NOT NULL,
|
||||
`time` INTEGER NOT NULL,
|
||||
`status` INTEGER NOT NULL,
|
||||
`source` INTEGER NOT NULL,
|
||||
`operationType` INTEGER NOT NULL,
|
||||
`amount` TEXT,
|
||||
`sender` TEXT,
|
||||
`receiver` TEXT,
|
||||
`hash` TEXT,
|
||||
`fee` TEXT,
|
||||
`isReward` INTEGER,
|
||||
`era` INTEGER,
|
||||
`validator` TEXT,
|
||||
`extrinsicContent_type` TEXT,
|
||||
`extrinsicContent_module` TEXT,
|
||||
`extrinsicContent_call` TEXT,
|
||||
PRIMARY KEY(`id`, `address`, `chainId`, `chainAssetId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import io.novafoundation.nova.core_db.model.chain.ChainLocal
|
||||
|
||||
val AddNodeSelectionStrategyField_38_39 = object : Migration(38, 39) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
val default = ChainLocal.Default.NODE_SELECTION_STRATEGY_DEFAULT
|
||||
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN `nodeSelectionStrategy` TEXT NOT NULL DEFAULT '$default'")
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddWalletConnectSessions_39_40 = object : Migration(39, 40) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `wallet_connect_sessions` (
|
||||
`sessionTopic` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
PRIMARY KEY(`sessionTopic`),
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_wallet_connect_sessions_metaId` ON `wallet_connect_sessions` (`metaId`)")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val ChangeAsset_3_4 = object : Migration(3, 4) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE assets")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `assets` (
|
||||
`tokenSymbol` TEXT NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`freeInPlanks` TEXT NOT NULL,
|
||||
`frozenInPlanks` TEXT NOT NULL,
|
||||
`reservedInPlanks` TEXT NOT NULL,
|
||||
`bondedInPlanks` TEXT NOT NULL,
|
||||
`redeemableInPlanks` TEXT NOT NULL,
|
||||
`unbondingInPlanks` TEXT NOT NULL,
|
||||
PRIMARY KEY(`tokenSymbol`, `chainId`, `metaId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_assets_metaId` ON `assets` (`metaId`)")
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddStakingDashboardItems_41_42 = object : Migration(41, 42) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `staking_dashboard_items` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`chainAssetId` INTEGER NOT NULL,
|
||||
`stakingType` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`hasStake` INTEGER NOT NULL,
|
||||
`stake` TEXT,
|
||||
`status` TEXT,
|
||||
`rewards` TEXT,
|
||||
`estimatedEarnings` REAL,
|
||||
`primaryStakingAccountId` BLOB,
|
||||
PRIMARY KEY(`chainId`, `chainAssetId`, `stakingType`, `metaId`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
FOREIGN KEY(`chainAssetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE ,
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_staking_dashboard_items_metaId` ON `staking_dashboard_items` (`metaId`)")
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val TransferFiatAmount_40_41 = object : Migration(40, 41) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
createCoinPriceTable(database)
|
||||
}
|
||||
|
||||
private fun createCoinPriceTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `coin_prices` (
|
||||
`priceId` TEXT NOT NULL,
|
||||
`currencyId` TEXT NOT NULL,
|
||||
`timestamp` INTEGER NOT NULL,
|
||||
`rate` TEXT NOT NULL,
|
||||
PRIMARY KEY(`priceId`, `currencyId`, `timestamp`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val StakingRewardPeriods_42_43 = object : Migration(42, 43) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
createCoinPriceTable(database)
|
||||
}
|
||||
|
||||
private fun createCoinPriceTable(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `staking_reward_period` (
|
||||
`accountId` BLOB NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`stakingType` TEXT NOT NULL,
|
||||
`periodType` TEXT NOT NULL,
|
||||
`customPeriodStart` INTEGER,
|
||||
`customPeriodEnd` INTEGER,
|
||||
PRIMARY KEY(`accountId`, `chainId`, `assetId`, `stakingType`))
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddRewardAccountToStakingDashboard_43_44 = object : Migration(43, 44) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE `staking_dashboard_items`")
|
||||
database.execSQL("DROP INDEX IF EXISTS `index_staking_dashboard_items_metaId`")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `staking_dashboard_items` (
|
||||
`chainId` TEXT NOT NULL,
|
||||
`chainAssetId` INTEGER NOT NULL,
|
||||
`stakingType` TEXT NOT NULL,
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`hasStake` INTEGER NOT NULL,
|
||||
`stake` TEXT,
|
||||
`status` TEXT,
|
||||
`rewards` TEXT,
|
||||
`estimatedEarnings` REAL,
|
||||
`stakeStatusAccount` BLOB,
|
||||
`rewardsAccount` BLOB,
|
||||
PRIMARY KEY(`chainId`, `chainAssetId`, `stakingType`, `metaId`),
|
||||
FOREIGN KEY(`chainId`) REFERENCES `chains`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
FOREIGN KEY(`chainAssetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
database.execSQL("CREATE INDEX IF NOT EXISTS `index_staking_dashboard_items_metaId` ON `staking_dashboard_items` (`metaId`)")
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddStakingTypeToTotalRewards_44_45 = object : Migration(44, 45) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("DROP TABLE total_reward")
|
||||
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `total_reward` (
|
||||
`accountId` BLOB NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`chainAssetId` INTEGER NOT NULL,
|
||||
`stakingType` TEXT NOT NULL,
|
||||
`totalReward` TEXT NOT NULL,
|
||||
PRIMARY KEY(`chainId`,`chainAssetId`,`stakingType`, `accountId`)
|
||||
)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddExternalBalances_45_46 = object : Migration(45, 46) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `externalBalances` (
|
||||
`metaId` INTEGER NOT NULL,
|
||||
`chainId` TEXT NOT NULL,
|
||||
`assetId` INTEGER NOT NULL,
|
||||
`type` TEXT NOT NULL,
|
||||
`subtype` TEXT NOT NULL,
|
||||
`amount` TEXT NOT NULL,
|
||||
PRIMARY KEY(`metaId`, `chainId`, `assetId`, `type`, `subtype`),
|
||||
FOREIGN KEY(`assetId`, `chainId`) REFERENCES `chain_assets`(`id`, `chainId`) ON UPDATE NO ACTION ON DELETE CASCADE,
|
||||
FOREIGN KEY(`metaId`) REFERENCES `meta_accounts`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddPoolIdToOperations_46_47 = object : Migration(46, 47) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE operations ADD COLUMN poolId INTEGER")
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddEventIdToOperation_47_48 = object : Migration(47, 48) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE operations ADD COLUMN eventId TEXT")
|
||||
|
||||
database.execSQL("DELETE FROM operations")
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package io.novafoundation.nova.core_db.migrations
|
||||
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
|
||||
val AddSwapOption_48_49 = object : Migration(48, 49) {
|
||||
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("ALTER TABLE chains ADD COLUMN `swap` TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user