- Modified equivalent_values table in order to work directly with fiat values

- Introduced version 3 of the database with said modifications
- Introduced basic db migration
This commit is contained in:
Nelson R. Perez 2019-01-31 15:09:02 -05:00
parent c7138c5e22
commit 622205069d
7 changed files with 479 additions and 18 deletions

View file

@ -22,6 +22,9 @@ android {
"$projectDir/schemas".toString()] "$projectDir/schemas".toString()]
} }
} }
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
} }
buildTypes { buildTypes {
release { release {
@ -60,7 +63,7 @@ android {
dependencies { dependencies {
def lifecycle_version = "2.0.0" def lifecycle_version = "2.0.0"
def room_version = "2.1.0-alpha03" def room_version = "2.1.0-alpha04"
def nav_version = "1.0.0-alpha11" def nav_version = "1.0.0-alpha11"
def rx_bindings_version = "3.0.0-alpha2" def rx_bindings_version = "3.0.0-alpha2"
@ -114,7 +117,7 @@ dependencies {
androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:core:1.1.0'
// testImplementation "androidx.arch.core:core-testing:$lifecycle_version" // testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
// testImplementation "androidx.room:room-testing:$room_version" androidTestImplementation "androidx.room:room-testing:$room_version"
// androidTestImplementation 'androidx.test:runner:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
} }

View file

@ -428,4 +428,4 @@
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"79a582fa39e989852699b131383e993a\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"79a582fa39e989852699b131383e993a\")"
] ]
} }
} }

View file

@ -0,0 +1,415 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "36ac924b7b8d78fb2d937d1ff9ba8897",
"entities": [
{
"tableName": "assets",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `symbol` TEXT NOT NULL, `precision` INTEGER NOT NULL, `description` TEXT NOT NULL, `bit_asset_id` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "symbol",
"columnName": "symbol",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "precision",
"columnName": "precision",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "bitAssetId",
"columnName": "bit_asset_id",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "authorities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `user_id` TEXT NOT NULL, `authority_type` INTEGER NOT NULL, `encrypted_wif` TEXT NOT NULL, `encrypted_brain_key` TEXT NOT NULL, `encrypted_sequence_number` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "userId",
"columnName": "user_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "authorityType",
"columnName": "authority_type",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "encryptedWIF",
"columnName": "encrypted_wif",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encryptedBrainKey",
"columnName": "encrypted_brain_key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "encryptedSequenceNumber",
"columnName": "encrypted_sequence_number",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": true
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "balances",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`asset_id` TEXT NOT NULL, `asset_amount` INTEGER NOT NULL, `last_update` INTEGER NOT NULL, PRIMARY KEY(`asset_id`))",
"fields": [
{
"fieldPath": "assetId",
"columnName": "asset_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "assetAmount",
"columnName": "asset_amount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastUpdate",
"columnName": "last_update",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"asset_id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "equivalent_values",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`transfer_id` TEXT NOT NULL, `value` INTEGER NOT NULL, `symbol` TEXT NOT NULL, PRIMARY KEY(`transfer_id`, `symbol`), FOREIGN KEY(`transfer_id`) REFERENCES `transfers`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [
{
"fieldPath": "transferId",
"columnName": "transfer_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "value",
"columnName": "value",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "symbol",
"columnName": "symbol",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"transfer_id",
"symbol"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": [
{
"table": "transfers",
"onDelete": "NO ACTION",
"onUpdate": "NO ACTION",
"columns": [
"transfer_id"
],
"referencedColumns": [
"id"
]
}
]
},
{
"tableName": "transfers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `block_number` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `fee_amount` INTEGER NOT NULL, `fee_asset_id` TEXT NOT NULL, `source` TEXT NOT NULL, `destination` TEXT NOT NULL, `transfer_amount` INTEGER NOT NULL, `transfer_asset_id` TEXT NOT NULL, `memo` TEXT NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "blockNumber",
"columnName": "block_number",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "feeAmount",
"columnName": "fee_amount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "feeAssetId",
"columnName": "fee_asset_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "source",
"columnName": "source",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "destination",
"columnName": "destination",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "transferAmount",
"columnName": "transfer_amount",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "transferAssetId",
"columnName": "transfer_asset_id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "memo",
"columnName": "memo",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "user_accounts",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `is_ltm` INTEGER NOT NULL, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isLtm",
"columnName": "is_ltm",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "merchants",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `address` TEXT, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `phone` TEXT, `telegram` TEXT, `website` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "_id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "address",
"columnName": "address",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "phone",
"columnName": "phone",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "telegram",
"columnName": "telegram",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "website",
"columnName": "website",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "tellers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `address` TEXT, `lat` REAL NOT NULL, `lon` REAL NOT NULL, `phone` TEXT, `telegram` TEXT, `website` TEXT, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "_id",
"columnName": "id",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "gt_name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "address",
"columnName": "address",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "lat",
"columnName": "lat",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "lon",
"columnName": "lon",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "phone",
"columnName": "phone",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "telegram",
"columnName": "telegram",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "website",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"columnNames": [
"id"
],
"autoGenerate": false
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"36ac924b7b8d78fb2d937d1ff9ba8897\")"
]
}
}

View file

@ -0,0 +1,40 @@
package cy.agorise.bitsybitshareswallet;
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import cy.agorise.bitsybitshareswallet.database.BitsyDatabase
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
@RunWith(AndroidJUnit4::class)
class MigrationTest {
private val TEST_DB = "migration-test"
@get:Rule
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
BitsyDatabase::class.java.canonicalName,
FrameworkSQLiteOpenHelperFactory()
)
@Test
@Throws(IOException::class)
fun migrate2To3() {
var db = helper.createDatabase(TEST_DB, 2).apply {
// db has schema version 1. insert some data using SQL queries.
// You cannot use DAO classes because they expect the latest schema.
execSQL("INSERT INTO assets(id, symbol, precision, description, bit_asset_id) VALUES('1.3.0','BTS', 5, '', '')")
execSQL("INSERT INTO transfers(id, block_number, timestamp, fee_amount, fee_asset_id, source, destination, transfer_amount, transfer_asset_id, memo) values(1,0,1500000000,120,'1.3.0','1.2.100','1.2.101',1000,'1.3.121','')")
execSQL("INSERT INTO equivalent_values(id, transfer_id, value, asset_id) values(1, 1, 100, '1.3.0')")
// Prepare for the next version.
close()
}
// Re-open the database with version 2 and provide
// MIGRATION_1_2 as the migration process.
db = helper.runMigrationsAndValidate(TEST_DB, 3, true, BitsyDatabase.MIGRATION_2_3)
}
}

View file

@ -140,7 +140,7 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection {
if (blockNumber != null && blockNumber != blockNumberWithMissingTime) { if (blockNumber != null && blockNumber != blockNumberWithMissingTime) {
blockNumberWithMissingTime = blockNumber blockNumberWithMissingTime = blockNumber
Log.d(TAG, "Block number: $blockNumber, Time: ${System.currentTimeMillis()}") Log.d(TAG, "Block number: $blockNumber, Time: ${System.currentTimeMillis()}")
mHandler.postDelayed(mRequestBlockMissingTimeTask, 10) mHandler.post(mRequestBlockMissingTimeTask)
} }
}) })

View file

@ -21,7 +21,7 @@ import cy.agorise.bitsybitshareswallet.database.joins.TransferDetailDao
Merchant::class, Merchant::class,
Teller::class Teller::class
], ],
version = 2, version = 3,
exportSchema = true) exportSchema = true)
abstract class BitsyDatabase : RoomDatabase() { abstract class BitsyDatabase : RoomDatabase() {
@ -48,18 +48,27 @@ abstract class BitsyDatabase : RoomDatabase() {
INSTANCE = Room.databaseBuilder( INSTANCE = Room.databaseBuilder(
context.applicationContext, context.applicationContext,
BitsyDatabase::class.java, "BiTSyWallet.db" BitsyDatabase::class.java, "BiTSyWallet.db"
).addMigrations(MIGRATION_1_2).build() ).addMigrations(MIGRATION_1_2)
.addMigrations(MIGRATION_2_3)
.build()
} }
} }
return INSTANCE return INSTANCE
} }
private val MIGRATION_1_2 = object : Migration(1, 2) { val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE IF NOT EXISTS 'merchants' ('id' TEXT NOT NULL PRIMARY KEY, 'name' TEXT NOT NULL, 'address' TEXT, 'lat' REAL NOT NULL, 'lon' REAL NOT NULL, 'phone' TEXT, 'telegram' TEXT, 'website' TEXT)") database.execSQL("CREATE TABLE IF NOT EXISTS 'merchants' ('id' TEXT NOT NULL PRIMARY KEY, 'name' TEXT NOT NULL, 'address' TEXT, 'lat' REAL NOT NULL, 'lon' REAL NOT NULL, 'phone' TEXT, 'telegram' TEXT, 'website' TEXT)")
database.execSQL("CREATE TABLE IF NOT EXISTS 'tellers' ('id' TEXT NOT NULL PRIMARY KEY, 'name' TEXT NOT NULL, 'address' TEXT, 'lat' REAL NOT NULL, 'lon' REAL NOT NULL, 'phone' TEXT, 'telegram' TEXT, 'website' TEXT)") database.execSQL("CREATE TABLE IF NOT EXISTS 'tellers' ('id' TEXT NOT NULL PRIMARY KEY, 'name' TEXT NOT NULL, 'address' TEXT, 'lat' REAL NOT NULL, 'lon' REAL NOT NULL, 'phone' TEXT, 'telegram' TEXT, 'website' TEXT)")
} }
} }
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE 'equivalent_values'")
database.execSQL("CREATE TABLE IF NOT EXISTS 'equivalent_values' ('transfer_id' TEXT NOT NULL, 'value' INTEGER NOT NULL, 'symbol' TEXT NOT NULL, PRIMARY KEY(transfer_id, symbol), FOREIGN KEY (transfer_id) REFERENCES transfers(id))")
}
}
} }
} }

View file

@ -3,23 +3,17 @@ package cy.agorise.bitsybitshareswallet.database.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.PrimaryKey
@Entity(tableName = "equivalent_values",foreignKeys = @Entity(tableName = "equivalent_values",
[ForeignKey( primaryKeys = arrayOf("transfer_id", "symbol"),
foreignKeys = [ForeignKey(
entity = Transfer::class, entity = Transfer::class,
parentColumns = ["id"], parentColumns = ["id"],
childColumns = ["transfer_id"] childColumns = ["transfer_id"]
), ForeignKey(
entity = Asset::class,
parentColumns = ["id"],
childColumns = ["asset_id"]
)] )]
) )
data class EquivalentValue ( data class EquivalentValue (
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id") val id: Long,
@ColumnInfo(name = "transfer_id") val transferId: String, @ColumnInfo(name = "transfer_id") val transferId: String,
@ColumnInfo(name = "value") val value: Long, @ColumnInfo(name = "value") val value: Long,
@ColumnInfo(name = "asset_id") val assetId: String @ColumnInfo(name = "symbol") val symbol: String
) )