From 65f94b1436961c6d6eed7e4933cede15891685f9 Mon Sep 17 00:00:00 2001 From: Alexis Hernandez Date: Mon, 5 Nov 2018 00:05:54 -0700 Subject: [PATCH] server: Add getLatestTransactionBy method to the TransactionDataHandler The method returns the latest transaction id for each of the given addresses. --- .../data/TransactionDataHandler.scala | 2 ++ .../TransactionPostgresDataHandler.scala | 6 +++++ .../anorm/dao/TransactionPostgresDAO.scala | 24 +++++++++++++++++++ .../async/TransactionFutureDataHandler.scala | 4 ++++ .../TransactionPostgresDataHandlerSpec.scala | 21 ++++++++++++++++ .../helpers/TransactionDummyDataHandler.scala | 2 ++ 6 files changed, 59 insertions(+) diff --git a/server/app/com/xsn/explorer/data/TransactionDataHandler.scala b/server/app/com/xsn/explorer/data/TransactionDataHandler.scala index a6dd409..6334d71 100644 --- a/server/app/com/xsn/explorer/data/TransactionDataHandler.scala +++ b/server/app/com/xsn/explorer/data/TransactionDataHandler.scala @@ -20,6 +20,8 @@ trait TransactionDataHandler[F[_]] { blockhash: Blockhash, paginatedQuery: PaginatedQuery, ordering: FieldOrdering[TransactionField]): F[PaginatedResult[TransactionWithValues]] + + def getLatestTransactionBy(addresses: List[Address]): F[Map[String, String]] } trait TransactionBlockingDataHandler extends TransactionDataHandler[ApplicationResult] diff --git a/server/app/com/xsn/explorer/data/anorm/TransactionPostgresDataHandler.scala b/server/app/com/xsn/explorer/data/anorm/TransactionPostgresDataHandler.scala index a6d3b0f..81cd29c 100644 --- a/server/app/com/xsn/explorer/data/anorm/TransactionPostgresDataHandler.scala +++ b/server/app/com/xsn/explorer/data/anorm/TransactionPostgresDataHandler.scala @@ -45,4 +45,10 @@ class TransactionPostgresDataHandler @Inject() ( Good(result) } + + def getLatestTransactionBy(addresses: List[Address]): ApplicationResult[Map[String, String]] = withConnection { implicit conn => + val result = transactionPostgresDAO.getLatestTransactionBy(addresses) + + Good(result) + } } diff --git a/server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala b/server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala index 26f3cb2..f7e02d7 100644 --- a/server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala +++ b/server/app/com/xsn/explorer/data/anorm/dao/TransactionPostgresDAO.scala @@ -206,6 +206,30 @@ class TransactionPostgresDAO @Inject() (fieldOrderingSQLInterpreter: FieldOrderi ).as(parseTransactionOutput.*).flatten } + def getLatestTransactionBy(addresses: List[Address])(implicit conn: Connection): Map[String, String] = { + + import SqlParser._ + + val result = SQL( + s""" + |SELECT address, ( + | SELECT txid + | FROM address_transaction_details + | WHERE address = a.address + | ORDER BY time DESC + | LIMIT 1 + |) AS txid + |FROM address_transaction_details a + |GROUP BY address + |HAVING address IN ({addresses}); + """.stripMargin + ).on( + 'addresses -> addresses.map(_.string) + ).as((str("address") ~ str("txid")).map(flatten).*) + + result.toMap + } + private def upsertTransaction(transaction: Transaction)(implicit conn: Connection): Option[Transaction] = { SQL( """ diff --git a/server/app/com/xsn/explorer/data/async/TransactionFutureDataHandler.scala b/server/app/com/xsn/explorer/data/async/TransactionFutureDataHandler.scala index 863e485..a12a6ef 100644 --- a/server/app/com/xsn/explorer/data/async/TransactionFutureDataHandler.scala +++ b/server/app/com/xsn/explorer/data/async/TransactionFutureDataHandler.scala @@ -35,4 +35,8 @@ class TransactionFutureDataHandler @Inject() ( blockingDataHandler.getByBlockhash(blockhash, paginatedQuery, ordering) } + + override def getLatestTransactionBy(addresses: List[Address]): FutureApplicationResult[Map[String, String]] = Future { + blockingDataHandler.getLatestTransactionBy(addresses) + } } diff --git a/server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala b/server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala index 85474d7..ebbabfb 100644 --- a/server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala +++ b/server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala @@ -296,6 +296,27 @@ class TransactionPostgresDataHandlerSpec extends PostgresDataHandlerSpec with Be } } + "getLatestTransactionBy" should { + "return the relation address -> latest txid" in { + clearDatabase() + val blocks = blockList + blocks.map(createBlock) + + val expected = Map( + "XcqpUChZhNkVDgQqFF9U4DdewDGUMWwG53" -> "41e315108dc2df60caddbc7e8740a5614217f996c96898019e69b3195fd7ee10", + "XdJnCKYNwzCz8ATv8Eu75gonaHyfr9qXg9" -> "1e591eae200f719344fc5df0c4286e3fb191fb8a645bdf054f9b36a856fce41e" + ) + + val addresses = List( + createAddress("XdJnCKYNwzCz8ATv8Eu75gonaHyfr9qXg9"), + createAddress("XcqpUChZhNkVDgQqFF9U4DdewDGUMWwG53"), + createAddress("XcqpUChZhNkVDgQqFF9U4DdewDGUMWwG54"), + ) + val result = dataHandler.getLatestTransactionBy(addresses).get + result mustEqual expected + } + } + private def createBlock(block: Block) = { val transactions = block.transactions .map(_.string) diff --git a/server/test/com/xsn/explorer/helpers/TransactionDummyDataHandler.scala b/server/test/com/xsn/explorer/helpers/TransactionDummyDataHandler.scala index df15090..2f5f4c8 100644 --- a/server/test/com/xsn/explorer/helpers/TransactionDummyDataHandler.scala +++ b/server/test/com/xsn/explorer/helpers/TransactionDummyDataHandler.scala @@ -13,4 +13,6 @@ class TransactionDummyDataHandler extends TransactionBlockingDataHandler { override def getUnspentOutputs(address: Address): ApplicationResult[List[Transaction.Output]] = ??? override def getByBlockhash(blockhash: Blockhash, paginatedQuery: PaginatedQuery, ordering: FieldOrdering[TransactionField]): ApplicationResult[PaginatedResult[TransactionWithValues]] = ??? + + override def getLatestTransactionBy(addresses: List[Address]): ApplicationResult[Map[String, String]] = ??? }