From 6a6cbf4048294fb94948f90b8aa3569dfd22fd7a Mon Sep 17 00:00:00 2001 From: Carter Jernigan Date: Wed, 2 Nov 2022 14:12:14 -0400 Subject: [PATCH] [#760] Fix database queries This resolves some query regressions that were introduced as part of [#705] --- .../ListTransactionsFragment.kt | 7 +- .../ecc/android/sdk/internal/db/CursorExt.kt | 8 +++ .../internal/db/derived/AllTransactionView.kt | 69 +++++++++++-------- .../db/derived/ReceivedTransactionView.kt | 53 +++++++------- .../db/derived/SentTransactionView.kt | 59 +++++++++------- .../z/ecc/android/sdk/model/Transaction.kt | 12 ++-- .../android/sdk/model/TransactionOverview.kt | 4 +- 7 files changed, 124 insertions(+), 88 deletions(-) diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt index 81d6e0ba..0b1c45d7 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/listtransactions/ListTransactionsFragment.kt @@ -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 = CursorParser { - val idColumnIndex = it.getColumnIndex(AllTransactionViewDefinition.COLUMN_INTEGER_ID) + private val cursorParser: CursorParser = 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) ) } diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/ReceivedTransactionView.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/ReceivedTransactionView.kt index 7b973448..8f64eeeb 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/ReceivedTransactionView.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/ReceivedTransactionView.kt @@ -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) ) } ) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/SentTransactionView.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/SentTransactionView.kt index c35b1962..374bd1d7 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/SentTransactionView.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/db/derived/SentTransactionView.kt @@ -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) ) } ) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/Transaction.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/Transaction.kt index e00f7c6b..e7afedfe 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/Transaction.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/Transaction.kt @@ -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, diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/TransactionOverview.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/TransactionOverview.kt index 0dfc597e..44e4ae93 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/TransactionOverview.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/TransactionOverview.kt @@ -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,