138 lines
5.0 KiB
Kotlin
138 lines
5.0 KiB
Kotlin
package cash.z.ecc.android.sdk.internal.db.derived
|
|
|
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
|
import cash.z.ecc.android.sdk.internal.db.queryAndMap
|
|
import cash.z.ecc.android.sdk.internal.model.EncodedTransaction
|
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
|
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.flow.first
|
|
import kotlinx.coroutines.flow.firstOrNull
|
|
import kotlinx.coroutines.withContext
|
|
import java.util.Locale
|
|
|
|
internal class TransactionTable(
|
|
private val zcashNetwork: ZcashNetwork,
|
|
private val sqliteDatabase: SupportSQLiteDatabase
|
|
) {
|
|
|
|
companion object {
|
|
private val SELECTION_BLOCK_IS_NULL = String.format(
|
|
Locale.ROOT,
|
|
"%s IS NULL", // $NON-NLS
|
|
TransactionTableDefinition.COLUMN_INTEGER_BLOCK
|
|
)
|
|
|
|
private val PROJECTION_COUNT = arrayOf("COUNT(*)") // $NON-NLS
|
|
|
|
private val PROJECTION_BLOCK = arrayOf(TransactionTableDefinition.COLUMN_INTEGER_BLOCK)
|
|
|
|
private val PROJECTION_PRIMARY_KEY_ID = arrayOf(TransactionTableDefinition.COLUMN_INTEGER_ID)
|
|
|
|
private val PROJECTION_ENCODED_TRANSACTION = arrayOf(
|
|
TransactionTableDefinition.COLUMN_BLOB_TRANSACTION_ID,
|
|
TransactionTableDefinition.COLUMN_BLOB_RAW,
|
|
TransactionTableDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT
|
|
)
|
|
|
|
private val SELECTION_RAW_TRANSACTION_ID = String.format(
|
|
Locale.ROOT,
|
|
"%s = ?", // $NON-NLS
|
|
TransactionTableDefinition.COLUMN_BLOB_TRANSACTION_ID
|
|
)
|
|
|
|
private val SELECTION_TRANSACTION_ID_AND_RAW_NOT_NULL = String.format(
|
|
Locale.ROOT,
|
|
"%s = ? AND %s IS NOT NULL", // $NON-NLS
|
|
TransactionTableDefinition.COLUMN_INTEGER_ID,
|
|
TransactionTableDefinition.COLUMN_BLOB_RAW
|
|
)
|
|
}
|
|
|
|
suspend fun count() = withContext(Dispatchers.IO) {
|
|
sqliteDatabase.queryAndMap(
|
|
table = TransactionTableDefinition.TABLE_NAME,
|
|
columns = PROJECTION_COUNT,
|
|
cursorParser = { it.getLong(0) }
|
|
).first()
|
|
}
|
|
|
|
suspend fun countUnmined() =
|
|
sqliteDatabase.queryAndMap(
|
|
table = TransactionTableDefinition.TABLE_NAME,
|
|
columns = PROJECTION_COUNT,
|
|
selection = SELECTION_BLOCK_IS_NULL,
|
|
cursorParser = { it.getLong(0) }
|
|
).first()
|
|
|
|
suspend fun findEncodedTransactionById(id: Long): EncodedTransaction? {
|
|
return sqliteDatabase.queryAndMap(
|
|
table = TransactionTableDefinition.TABLE_NAME,
|
|
columns = PROJECTION_ENCODED_TRANSACTION,
|
|
selection = SELECTION_TRANSACTION_ID_AND_RAW_NOT_NULL,
|
|
selectionArgs = arrayOf(id)
|
|
) {
|
|
val txIdIndex = it.getColumnIndexOrThrow(TransactionTableDefinition.COLUMN_BLOB_TRANSACTION_ID)
|
|
val rawIndex = it.getColumnIndexOrThrow(TransactionTableDefinition.COLUMN_BLOB_RAW)
|
|
val heightIndex = it.getColumnIndexOrThrow(TransactionTableDefinition.COLUMN_INTEGER_EXPIRY_HEIGHT)
|
|
|
|
val txid = it.getBlob(txIdIndex)
|
|
val raw = it.getBlob(rawIndex)
|
|
val expiryHeight = if (it.isNull(heightIndex)) {
|
|
null
|
|
} else {
|
|
BlockHeight.new(zcashNetwork, it.getLong(heightIndex))
|
|
}
|
|
|
|
EncodedTransaction(
|
|
FirstClassByteArray(txid),
|
|
FirstClassByteArray(raw),
|
|
expiryHeight
|
|
)
|
|
}.firstOrNull()
|
|
}
|
|
|
|
suspend fun findMinedHeight(rawTransactionId: ByteArray): BlockHeight? {
|
|
return sqliteDatabase.queryAndMap(
|
|
table = TransactionTableDefinition.TABLE_NAME,
|
|
columns = PROJECTION_BLOCK,
|
|
selection = SELECTION_RAW_TRANSACTION_ID,
|
|
selectionArgs = arrayOf(rawTransactionId)
|
|
) {
|
|
val blockIndex = it.getColumnIndexOrThrow(TransactionTableDefinition.COLUMN_INTEGER_BLOCK)
|
|
BlockHeight.new(zcashNetwork, it.getLong(blockIndex))
|
|
}.firstOrNull()
|
|
}
|
|
|
|
suspend fun findDatabaseId(rawTransactionId: ByteArray): Long? {
|
|
return sqliteDatabase.queryAndMap(
|
|
table = TransactionTableDefinition.TABLE_NAME,
|
|
columns = PROJECTION_PRIMARY_KEY_ID,
|
|
selection = SELECTION_RAW_TRANSACTION_ID,
|
|
selectionArgs = arrayOf(rawTransactionId)
|
|
) {
|
|
val idIndex = it.getColumnIndexOrThrow(TransactionTableDefinition.COLUMN_INTEGER_ID)
|
|
it.getLong(idIndex)
|
|
}.firstOrNull()
|
|
}
|
|
}
|
|
|
|
object TransactionTableDefinition {
|
|
const val TABLE_NAME = "transactions" // $NON-NLS
|
|
|
|
const val COLUMN_INTEGER_ID = "id_tx" // $NON-NLS
|
|
|
|
const val COLUMN_BLOB_TRANSACTION_ID = "txid" // $NON-NLS
|
|
|
|
const val COLUMN_TEXT_CREATED = "created" // $NON-NLS
|
|
|
|
const val COLUMN_INTEGER_BLOCK = "block" // $NON-NLS
|
|
|
|
const val COLUMN_INTEGER_TX_INDEX = "tx_index" // $NON-NLS
|
|
|
|
const val COLUMN_INTEGER_EXPIRY_HEIGHT = "expiry_height" // $NON-NLS
|
|
|
|
const val COLUMN_BLOB_RAW = "raw" // $NON-NLS
|
|
}
|