Skip to content

Commit

Permalink
Uniques nfts initial sync
Browse files Browse the repository at this point in the history
  • Loading branch information
valentunn committed Feb 24, 2022
1 parent 1accd1d commit 3eedfbd
Show file tree
Hide file tree
Showing 28 changed files with 509 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.novafoundation.nova.common.utils

interface Identifiable {

val identifier: String
}

object CollectionDiffer {

class Diff<T>(
val newOrUpdated: List<T>,
val removed: List<T>
)

fun <T : Identifiable> findDiff(newItems: List<T>, oldItems: List<T>): Diff<T> {

val newKeys: Set<String> = newItems.mapTo(mutableSetOf()) { it.identifier }
val oldMapping = oldItems.associateBy { it.identifier }

val newOrUpdated = newItems.mapNotNull { new ->
val old = oldMapping[new.identifier]

when {
old == null -> new // new
old != new -> new // updated
else -> null // same
}
}

val removed = oldItems.filter { it.identifier !in newKeys }

return Diff(newOrUpdated, removed)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,12 @@ fun <T> List<T>.modified(index: Int, modification: T): List<T> {

return newList
}

@Suppress("IfThenToElvis")
fun ByteArray?.optionalContentEquals(other: ByteArray?): Boolean {
return if (this == null) {
other == null
} else {
this.contentEquals(other)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.room.TypeConverters
import io.novafoundation.nova.core_db.converters.CryptoTypeConverters
import io.novafoundation.nova.core_db.converters.LongMathConverters
import io.novafoundation.nova.core_db.converters.NetworkTypeConverters
import io.novafoundation.nova.core_db.converters.NftTypeConverters
import io.novafoundation.nova.core_db.converters.OperationConverters
import io.novafoundation.nova.core_db.converters.TokenConverters
import io.novafoundation.nova.core_db.dao.AccountDao
Expand All @@ -16,6 +17,7 @@ import io.novafoundation.nova.core_db.dao.AssetDao
import io.novafoundation.nova.core_db.dao.ChainDao
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
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
Expand All @@ -24,12 +26,14 @@ import io.novafoundation.nova.core_db.dao.StorageDao
import io.novafoundation.nova.core_db.dao.TokenDao
import io.novafoundation.nova.core_db.migrations.AddChainColor_4_5
import io.novafoundation.nova.core_db.migrations.AddDAppAuthorizations_1_2
import io.novafoundation.nova.core_db.migrations.AddNfts_5_6
import io.novafoundation.nova.core_db.migrations.AssetTypes_2_3
import io.novafoundation.nova.core_db.migrations.ChangeAsset_3_4
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.DappAuthorizationLocal
import io.novafoundation.nova.core_db.model.NftLocal
import io.novafoundation.nova.core_db.model.NodeLocal
import io.novafoundation.nova.core_db.model.OperationLocal
import io.novafoundation.nova.core_db.model.PhishingAddressLocal
Expand All @@ -45,7 +49,7 @@ import io.novafoundation.nova.core_db.model.chain.ChainRuntimeInfoLocal
import io.novafoundation.nova.core_db.model.chain.MetaAccountLocal

@Database(
version = 5,
version = 6,
entities = [
AccountLocal::class,
NodeLocal::class,
Expand All @@ -65,15 +69,17 @@ import io.novafoundation.nova.core_db.model.chain.MetaAccountLocal
MetaAccountLocal::class,
ChainAccountLocal::class,

DappAuthorizationLocal::class
DappAuthorizationLocal::class,
NftLocal::class,
],
)
@TypeConverters(
LongMathConverters::class,
NetworkTypeConverters::class,
TokenConverters::class,
OperationConverters::class,
CryptoTypeConverters::class
CryptoTypeConverters::class,
NftTypeConverters::class
)

abstract class AppDatabase : RoomDatabase() {
Expand All @@ -92,7 +98,7 @@ abstract class AppDatabase : RoomDatabase() {
AppDatabase::class.java, "app.db"
)
.addMigrations(AddDAppAuthorizations_1_2, AssetTypes_2_3, ChangeAsset_3_4)
.addMigrations(AddChainColor_4_5)
.addMigrations(AddChainColor_4_5, AddNfts_5_6)
.fallbackToDestructiveMigration()
.build()
}
Expand Down Expand Up @@ -123,4 +129,6 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun metaAccountDao(): MetaAccountDao

abstract fun dAppAuthorizationDao(): DappAuthorizationDao

abstract fun nftDao(): NftDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.novafoundation.nova.core_db.converters

import androidx.room.TypeConverter
import io.novafoundation.nova.core_db.model.NftLocal

class NftTypeConverters {

@TypeConverter
fun from(type: NftLocal.Type): String {
return type.name
}

@TypeConverter
fun to(name: String): NftLocal.Type {
return enumValueOf(name)
}
}
42 changes: 42 additions & 0 deletions core-db/src/main/java/io/novafoundation/nova/core_db/dao/NftDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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
interface NftDao {

@Query("SELECT * FROM nfts WHERE metaId = :metaId")
fun nftsFlow(metaId: Long): Flow<List<NftLocal>>

@Query("SELECT * FROM nfts WHERE metaId = :metaId AND type = :type")
suspend fun getNfts(metaId: Long, type: NftLocal.Type): List<NftLocal>

@Delete
suspend fun deleteNfts(nfts: List<NftLocal>)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertNfts(nfts: List<NftLocal>)

@Update
suspend fun updateNft(nft: NftLocal)

@Transaction
suspend fun insertNftsDiff(nftType: NftLocal.Type, metaId: Long, newNfts: List<NftLocal>) {
val oldNfts = getNfts(metaId, nftType)

val diff = CollectionDiffer.findDiff(newNfts, oldNfts)

deleteNfts(diff.removed)

insertNfts(diff.newOrUpdated)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.novafoundation.nova.core_db.dao.AssetDao
import io.novafoundation.nova.core_db.dao.ChainDao
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
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
Expand Down Expand Up @@ -41,4 +42,6 @@ interface DbApi {
fun metaAccountDao(): MetaAccountDao

fun dappAuthorizationDao(): DappAuthorizationDao

fun nftDao(): NftDao
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.novafoundation.nova.core_db.dao.AssetDao
import io.novafoundation.nova.core_db.dao.ChainDao
import io.novafoundation.nova.core_db.dao.DappAuthorizationDao
import io.novafoundation.nova.core_db.dao.MetaAccountDao
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
Expand Down Expand Up @@ -100,4 +101,10 @@ class DbModule {
fun provideDappAuthorizationDao(appDatabase: AppDatabase): DappAuthorizationDao {
return appDatabase.dAppAuthorizationDao()
}

@Provides
@ApplicationScope
fun provideNftDao(appDatabase: AppDatabase): NftDao {
return appDatabase.nftDao()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.novafoundation.nova.core_db.migrations

import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

val AddNfts_5_6 = object : Migration(5, 6) {

override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS `nfts` (
`identifier` TEXT NOT NULL,
`metaId` INTEGER NOT NULL,
`chainId` TEXT NOT NULL,
`collectionId` TEXT,
`instanceId` TEXT,
`metadata` BLOB,
`name` TEXT,
`label` TEXT,
`media` TEXT,
`price` TEXT,
`type` TEXT NOT NULL,
PRIMARY KEY(`identifier`))
"""
)
database.execSQL("CREATE INDEX IF NOT EXISTS `index_nfts_metaId` ON `nfts` (`metaId`)")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.novafoundation.nova.core_db.model

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.novafoundation.nova.common.utils.Identifiable
import io.novafoundation.nova.common.utils.optionalContentEquals
import java.math.BigInteger

@Entity(tableName = "nfts")
class NftLocal(
@PrimaryKey
override val identifier: String,
@ColumnInfo(index = true)
val metaId: Long,
val chainId: String,
val collectionId: String?,
val instanceId: String?,
val metadata: ByteArray?,
// --- metadata fields ---
// name is always be present. null in case it is not loaded (nft is partially loaded)
val name: String? = null,
val label: String? = null,
val media: String? = null,
val price: BigInteger? = null,
// --- metadata fields ---

val type: Type
): Identifiable {

enum class Type {
UNIQUES, RMRK1
}

override fun equals(other: Any?): Boolean {
return other is NftLocal &&
identifier == other.identifier &&
// metadata is either direct data or a link to immutable distributed storage
metadata.optionalContentEquals(other.metadata)
&& price == other.price
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import io.novafoundation.nova.feature_account_api.domain.interfaces.AccountRepos
import io.novafoundation.nova.feature_account_api.domain.interfaces.SelectedAccountUseCase
import io.novafoundation.nova.feature_account_api.presenatation.account.AddressDisplayUseCase
import io.novafoundation.nova.feature_account_api.presenatation.actions.ExternalActions
import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.tranfers.AssetTransfersProvider
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletConstants
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository
Expand Down Expand Up @@ -99,4 +100,6 @@ interface AssetsFeatureDependencies {
fun walletConstants(): WalletConstants

fun assetTransfersProvider(): AssetTransfersProvider

fun nftRepository(): NftRepository
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.novafoundation.nova.feature_assets.domain.WalletInteractorImpl
import io.novafoundation.nova.feature_assets.presentation.balance.assetActions.buy.BuyMixin
import io.novafoundation.nova.feature_assets.presentation.balance.assetActions.buy.BuyMixinProvider
import io.novafoundation.nova.feature_assets.presentation.transaction.filter.HistoryFiltersProvider
import io.novafoundation.nova.feature_nft_api.data.repository.NftRepository
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.WalletRepository
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry

Expand All @@ -36,11 +37,13 @@ class AssetsFeatureModule {
accountRepository: AccountRepository,
assetFiltersRepository: AssetFiltersRepository,
chainRegistry: ChainRegistry,
nftRepository: NftRepository,
): WalletInteractor = WalletInteractorImpl(
walletRepository,
accountRepository,
assetFiltersRepository,
chainRegistry
chainRegistry,
nftRepository
)

@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.novafoundation.nova.feature_assets.domain

import io.novafoundation.nova.common.data.model.CursorPage
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
import io.novafoundation.nova.feature_wallet_api.domain.interfaces.TransactionFilter
import io.novafoundation.nova.feature_wallet_api.domain.model.Asset
import io.novafoundation.nova.feature_wallet_api.domain.model.Balances
Expand All @@ -13,7 +14,9 @@ interface WalletInteractor {

fun balancesFlow(): Flow<Balances>

suspend fun syncAssetsRates(): Result<Unit>
suspend fun syncAssetsRates()

suspend fun syncNfts(metaAccount: MetaAccount)

fun assetFlow(chainId: ChainId, chainAssetId: Int): Flow<Asset>

Expand Down
Loading

0 comments on commit 3eedfbd

Please sign in to comment.