[#760] Fix database queries

This resolves some query regressions that were introduced as part of [#705]
This commit is contained in:
Carter Jernigan 2022-11-02 14:12:14 -04:00 committed by Carter Jernigan
parent 5fb5773a7d
commit 6a6cbf4048
7 changed files with 124 additions and 88 deletions

View File

@ -22,8 +22,6 @@ import cash.z.ecc.android.sdk.model.TransactionOverview
import cash.z.ecc.android.sdk.model.ZcashNetwork
import cash.z.ecc.android.sdk.model.defaultForNetwork
import cash.z.ecc.android.sdk.tool.DerivationTool
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
/**
@ -82,9 +80,8 @@ class ListTransactionsFragment : BaseDemoFragment<FragmentListTransactionsBindin
synchronizer.processorInfo.collectWith(lifecycleScope, ::onProcessorInfoUpdated)
synchronizer.progress.collectWith(lifecycleScope, ::onProgress)
lifecycleScope.launch {
val transactions = synchronizer.clearedTransactions.first()
onTransactionsUpdated(transactions)
synchronizer.clearedTransactions.collectWith(lifecycleScope) {
onTransactionsUpdated(it)
}
}

View File

@ -10,3 +10,11 @@ internal fun Cursor.optLong(columnIndex: Int): Long? =
} else {
getLong(columnIndex)
}
internal fun Cursor.optBlobOrThrow(index: Int): ByteArray? {
return if (isNull(index)) {
null
} else {
getBlob(index)
}
}

View File

@ -2,6 +2,7 @@ package cash.z.ecc.android.sdk.internal.db.derived
import androidx.sqlite.db.SupportSQLiteDatabase
import cash.z.ecc.android.sdk.internal.db.CursorParser
import cash.z.ecc.android.sdk.internal.db.optBlobOrThrow
import cash.z.ecc.android.sdk.internal.db.queryAndMap
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.FirstClassByteArray
@ -36,45 +37,55 @@ internal class AllTransactionView(
private val PROJECTION_COUNT = arrayOf("COUNT(*)") // $NON-NLS
}
private val cursorParser: CursorParser<TransactionOverview> = CursorParser {
val idColumnIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_ID)
private val cursorParser: CursorParser<TransactionOverview> = CursorParser { cursor ->
val idColumnIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_ID)
val minedHeightColumnIndex =
it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = it.getColumnIndex(
cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = cursor.getColumnIndex(
AllTransactionViewDefinition.COLUMN_INTEGER_TRANSACTION_INDEX
)
val rawTransactionIdIndex =
it.getColumnIndex(AllTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT)
val rawIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_BLOB_RAW)
val netValueIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_LONG_VALUE)
val feePaidIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_LONG_FEE_PAID)
val isChangeIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_BOOLEAN_IS_CHANGE)
val isWalletInternalIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_BOOLEAN_IS_WALLET_INTERNAL)
val receivedNoteCountIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_NOTE_COUNT)
val sentNoteCountIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_SENT_NOTE_COUNT)
val memoCountIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT)
val rawIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_BLOB_RAW)
val netValueIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_LONG_VALUE)
val feePaidIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_LONG_FEE_PAID)
val isChangeIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_BOOLEAN_IS_CHANGE)
val isWalletInternalIndex = cursor.getColumnIndex(
AllTransactionViewDefinition.COLUMN_BOOLEAN_IS_WALLET_INTERNAL
)
val receivedNoteCountIndex = cursor.getColumnIndex(
AllTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_NOTE_COUNT
)
val sentNoteCountIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_SENT_NOTE_COUNT)
val memoCountIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = cursor.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
val netValueLong = it.getLong(netValueIndex)
val netValueLong = cursor.getLong(netValueIndex)
val isSent = netValueLong < 0
val expiryHeightLong = cursor.getLong(expiryHeightIndex)
TransactionOverview(
id = it.getLong(idColumnIndex),
rawId = FirstClassByteArray(it.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, it.getLong(minedHeightColumnIndex)),
expiryHeight = BlockHeight.new(zcashNetwork, it.getLong(expiryHeightIndex)),
index = it.getLong(transactionIndexColumnIndex),
raw = FirstClassByteArray(it.getBlob(rawIndex)),
id = cursor.getLong(idColumnIndex),
rawId = FirstClassByteArray(cursor.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, cursor.getLong(minedHeightColumnIndex)),
expiryHeight = if (0L == expiryHeightLong) {
null
} else {
BlockHeight.new(zcashNetwork, expiryHeightLong)
},
index = cursor.getLong(transactionIndexColumnIndex),
raw = cursor.optBlobOrThrow(rawIndex)?.let { FirstClassByteArray(it) },
isSentTransaction = isSent,
netValue = Zatoshi(netValueLong.absoluteValue),
feePaid = Zatoshi(it.getLong(feePaidIndex)),
isChange = it.getInt(isChangeIndex) != 0,
isWalletInternal = it.getInt(isWalletInternalIndex) != 0,
receivedNoteCount = it.getInt(receivedNoteCountIndex),
sentNoteCount = it.getInt(sentNoteCountIndex),
memoCount = it.getInt(memoCountIndex),
blockTimeEpochSeconds = it.getLong(blockTimeIndex)
feePaid = Zatoshi(cursor.getLong(feePaidIndex)),
isChange = cursor.getInt(isChangeIndex) != 0,
isWalletInternal = cursor.getInt(isWalletInternalIndex) != 0,
receivedNoteCount = cursor.getInt(receivedNoteCountIndex),
sentNoteCount = cursor.getInt(sentNoteCountIndex),
memoCount = cursor.getInt(memoCountIndex),
blockTimeEpochSeconds = cursor.getLong(blockTimeIndex)
)
}

View File

@ -1,6 +1,7 @@
package cash.z.ecc.android.sdk.internal.db.derived
import androidx.sqlite.db.SupportSQLiteDatabase
import cash.z.ecc.android.sdk.internal.db.optBlobOrThrow
import cash.z.ecc.android.sdk.internal.db.queryAndMap
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
@ -37,42 +38,48 @@ internal class ReceivedTransactionView(
sqliteDatabase.queryAndMap(
table = ReceivedTransactionViewDefinition.VIEW_NAME,
orderBy = ORDER_BY,
cursorParser = {
val idColumnIndex = it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_ID)
cursorParser = { cursor ->
val idColumnIndex = cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_ID)
val minedHeightColumnIndex =
it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = it.getColumnIndex(
cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = cursor.getColumnIndex(
ReceivedTransactionViewDefinition
.COLUMN_INTEGER_TRANSACTION_INDEX
)
val rawTransactionIdIndex =
it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = it.getColumnIndex(
cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = cursor.getColumnIndex(
ReceivedTransactionViewDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT
)
val rawIndex = it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_BLOB_RAW)
val receivedAccountIndex = it.getColumnIndex(
val rawIndex = cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_BLOB_RAW)
val receivedAccountIndex = cursor.getColumnIndex(
ReceivedTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_BY_ACCOUNT
)
val receivedTotalIndex =
it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_TOTAL)
cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_TOTAL)
val receivedNoteCountIndex =
it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_NOTE_COUNT)
val memoCountIndex = it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = it.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_RECEIVED_NOTE_COUNT)
val memoCountIndex = cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = cursor.getColumnIndex(ReceivedTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
val expiryHeightLong = cursor.getLong(expiryHeightIndex)
Transaction.Received(
id = it.getLong(idColumnIndex),
rawId = FirstClassByteArray(it.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, it.getLong(minedHeightColumnIndex)),
expiryHeight = BlockHeight.new(zcashNetwork, it.getLong(expiryHeightIndex)),
index = it.getLong(transactionIndexColumnIndex),
raw = FirstClassByteArray(it.getBlob(rawIndex)),
receivedByAccount = Account(it.getInt(receivedAccountIndex)),
receivedTotal = Zatoshi(it.getLong(receivedTotalIndex)),
receivedNoteCount = it.getInt(receivedNoteCountIndex),
memoCount = it.getInt(memoCountIndex),
blockTimeEpochSeconds = it.getLong(blockTimeIndex)
id = cursor.getLong(idColumnIndex),
rawId = FirstClassByteArray(cursor.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, cursor.getLong(minedHeightColumnIndex)),
expiryHeight = if (0L == expiryHeightLong) {
null
} else {
BlockHeight.new(zcashNetwork, expiryHeightLong)
},
index = cursor.getLong(transactionIndexColumnIndex),
raw = cursor.optBlobOrThrow(rawIndex)?.let { FirstClassByteArray(it) },
receivedByAccount = Account(cursor.getInt(receivedAccountIndex)),
receivedTotal = Zatoshi(cursor.getLong(receivedTotalIndex)),
receivedNoteCount = cursor.getInt(receivedNoteCountIndex),
memoCount = cursor.getInt(memoCountIndex),
blockTimeEpochSeconds = cursor.getLong(blockTimeIndex)
)
}
)

View File

@ -1,6 +1,7 @@
package cash.z.ecc.android.sdk.internal.db.derived
import androidx.sqlite.db.SupportSQLiteDatabase
import cash.z.ecc.android.sdk.internal.db.optBlobOrThrow
import cash.z.ecc.android.sdk.internal.db.queryAndMap
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
@ -37,36 +38,48 @@ internal class SentTransactionView(
sqliteDatabase.queryAndMap(
table = SentTransactionViewDefinition.VIEW_NAME,
orderBy = ORDER_BY,
cursorParser = {
val idColumnIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_ID)
cursorParser = { cursor ->
val idColumnIndex = cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_ID)
val minedHeightColumnIndex =
it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = it.getColumnIndex(
cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_MINED_HEIGHT)
val transactionIndexColumnIndex = cursor.getColumnIndex(
SentTransactionViewDefinition
.COLUMN_INTEGER_TRANSACTION_INDEX
)
val rawTransactionIdIndex =
it.getColumnIndex(SentTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT)
val rawIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_BLOB_RAW)
val sentFromAccount = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_SENT_FROM_ACCOUNT)
val sentTotalIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_SENT_TOTAL)
val sentNoteCountIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_SENT_NOTE_COUNT)
val memoCountIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = it.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_BLOB_RAW_TRANSACTION_ID)
val expiryHeightIndex = cursor.getColumnIndex(
SentTransactionViewDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT
)
val rawIndex = cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_BLOB_RAW)
val sentFromAccount = cursor.getColumnIndex(
SentTransactionViewDefinition.COLUMN_INTEGER_SENT_FROM_ACCOUNT
)
val sentTotalIndex = cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_SENT_TOTAL)
val sentNoteCountIndex = cursor.getColumnIndex(
SentTransactionViewDefinition.COLUMN_INTEGER_SENT_NOTE_COUNT
)
val memoCountIndex = cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_MEMO_COUNT)
val blockTimeIndex = cursor.getColumnIndex(SentTransactionViewDefinition.COLUMN_INTEGER_BLOCK_TIME)
val expiryHeightLong = cursor.getLong(expiryHeightIndex)
Transaction.Sent(
id = it.getLong(idColumnIndex),
rawId = FirstClassByteArray(it.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, it.getLong(minedHeightColumnIndex)),
expiryHeight = BlockHeight.new(zcashNetwork, it.getLong(expiryHeightIndex)),
index = it.getLong(transactionIndexColumnIndex),
raw = FirstClassByteArray(it.getBlob(rawIndex)),
sentFromAccount = Account(it.getInt(sentFromAccount)),
sentTotal = Zatoshi(it.getLong(sentTotalIndex)),
sentNoteCount = it.getInt(sentNoteCountIndex),
memoCount = it.getInt(memoCountIndex),
blockTimeEpochSeconds = it.getLong(blockTimeIndex)
id = cursor.getLong(idColumnIndex),
rawId = FirstClassByteArray(cursor.getBlob(rawTransactionIdIndex)),
minedHeight = BlockHeight.new(zcashNetwork, cursor.getLong(minedHeightColumnIndex)),
expiryHeight = if (0L == expiryHeightLong) {
null
} else {
BlockHeight.new(zcashNetwork, expiryHeightLong)
},
index = cursor.getLong(transactionIndexColumnIndex),
raw = cursor.optBlobOrThrow(rawIndex)?.let { FirstClassByteArray(it) },
sentFromAccount = Account(cursor.getInt(sentFromAccount)),
sentTotal = Zatoshi(cursor.getLong(sentTotalIndex)),
sentNoteCount = cursor.getInt(sentNoteCountIndex),
memoCount = cursor.getInt(memoCountIndex),
blockTimeEpochSeconds = cursor.getLong(blockTimeIndex)
)
}
)

View File

@ -1,13 +1,13 @@
package cash.z.ecc.android.sdk.model
sealed class Transaction {
data class Received(
data class Received internal constructor(
val id: Long,
val rawId: FirstClassByteArray,
val minedHeight: BlockHeight,
val expiryHeight: BlockHeight,
val expiryHeight: BlockHeight?,
val index: Long,
val raw: FirstClassByteArray,
val raw: FirstClassByteArray?,
val receivedByAccount: Account,
val receivedTotal: Zatoshi,
val receivedNoteCount: Int,
@ -17,13 +17,13 @@ sealed class Transaction {
override fun toString() = "ReceivedTransaction"
}
data class Sent(
data class Sent internal constructor(
val id: Long,
val rawId: FirstClassByteArray,
val minedHeight: BlockHeight,
val expiryHeight: BlockHeight,
val expiryHeight: BlockHeight?,
val index: Long,
val raw: FirstClassByteArray,
val raw: FirstClassByteArray?,
val sentFromAccount: Account,
val sentTotal: Zatoshi,
val sentNoteCount: Int,

View File

@ -9,9 +9,9 @@ data class TransactionOverview internal constructor(
val id: Long,
val rawId: FirstClassByteArray,
val minedHeight: BlockHeight,
val expiryHeight: BlockHeight,
val expiryHeight: BlockHeight?,
val index: Long,
val raw: FirstClassByteArray,
val raw: FirstClassByteArray?,
val isSentTransaction: Boolean,
val netValue: Zatoshi,
val feePaid: Zatoshi,