From 1a59506179034faf6e1823623b0d947a35421e2e Mon Sep 17 00:00:00 2001 From: Alexis Hernandez Date: Sun, 15 Apr 2018 00:30:14 -0500 Subject: [PATCH] server: Allow to specify ordering on GET /balances --- .../xsn/explorer/data/BalanceDataHandler.scala | 5 +++-- .../anorm/BalancePostgresDataHandler.scala | 10 +++++++--- .../data/anorm/dao/BalancePostgresDAO.scala | 18 +++++++++++++----- .../data/async/BalanceFutureDataHandler.scala | 7 ++++--- .../xsn/explorer/services/BalanceService.scala | 11 +++++++---- .../app/controllers/BalancesController.scala | 10 ++++++---- server/conf/routes | 2 +- .../data/BalancePostgresDataHandlerSpec.scala | 14 +++++++++----- .../processors/BlockEventsProcessorSpec.scala | 3 ++- .../controllers/BalancesControllerSpec.scala | 3 ++- 10 files changed, 54 insertions(+), 29 deletions(-) diff --git a/server/app/com/xsn/explorer/data/BalanceDataHandler.scala b/server/app/com/xsn/explorer/data/BalanceDataHandler.scala index 5a38801..22a62e9 100644 --- a/server/app/com/xsn/explorer/data/BalanceDataHandler.scala +++ b/server/app/com/xsn/explorer/data/BalanceDataHandler.scala @@ -2,7 +2,8 @@ package com.xsn.explorer.data import com.alexitc.playsonify.core.ApplicationResult import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.base.{FieldOrdering, PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.fields.BalanceField import scala.language.higherKinds @@ -10,7 +11,7 @@ trait BalanceDataHandler[F[_]] { def upsert(balance: Balance): F[Balance] - def getRichest(query: PaginatedQuery): F[PaginatedResult[Balance]] + def get(query: PaginatedQuery, ordering: FieldOrdering[BalanceField]): F[PaginatedResult[Balance]] } trait BalanceBlockingDataHandler extends BalanceDataHandler[ApplicationResult] diff --git a/server/app/com/xsn/explorer/data/anorm/BalancePostgresDataHandler.scala b/server/app/com/xsn/explorer/data/anorm/BalancePostgresDataHandler.scala index ba26cf4..c9aa873 100644 --- a/server/app/com/xsn/explorer/data/anorm/BalancePostgresDataHandler.scala +++ b/server/app/com/xsn/explorer/data/anorm/BalancePostgresDataHandler.scala @@ -7,7 +7,8 @@ import com.xsn.explorer.data.BalanceBlockingDataHandler import com.xsn.explorer.data.anorm.dao.BalancePostgresDAO import com.xsn.explorer.errors.BalanceUnknownError import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.base.{FieldOrdering, PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.fields.BalanceField import org.scalactic.{Good, One, Or} import play.api.db.Database @@ -23,8 +24,11 @@ class BalancePostgresDataHandler @Inject() ( Or.from(maybe, One(BalanceUnknownError)) } - override def getRichest(query: PaginatedQuery): ApplicationResult[PaginatedResult[Balance]] = withConnection { implicit conn => - val balances = balancePostgresDAO.getRichest(query) + override def get( + query: PaginatedQuery, + ordering: FieldOrdering[BalanceField]): ApplicationResult[PaginatedResult[Balance]] = withConnection { implicit conn => + + val balances = balancePostgresDAO.get(query, ordering) val total = balancePostgresDAO.countRichest val result = PaginatedResult(query.offset, query.limit, total, balances) diff --git a/server/app/com/xsn/explorer/data/anorm/dao/BalancePostgresDAO.scala b/server/app/com/xsn/explorer/data/anorm/dao/BalancePostgresDAO.scala index 5b3be13..47bcbf2 100644 --- a/server/app/com/xsn/explorer/data/anorm/dao/BalancePostgresDAO.scala +++ b/server/app/com/xsn/explorer/data/anorm/dao/BalancePostgresDAO.scala @@ -1,13 +1,16 @@ package com.xsn.explorer.data.anorm.dao import java.sql.Connection +import javax.inject.Inject import anorm._ +import com.xsn.explorer.data.anorm.interpreters.FieldOrderingSQLInterpreter import com.xsn.explorer.data.anorm.parsers.BalanceParsers._ import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{Count, PaginatedQuery} +import com.xsn.explorer.models.base.{Count, FieldOrdering, PaginatedQuery} +import com.xsn.explorer.models.fields.BalanceField -class BalancePostgresDAO { +class BalancePostgresDAO @Inject() (fieldOrderingSQLInterpreter: FieldOrderingSQLInterpreter) { def upsert(balance: Balance)(implicit conn: Connection): Option[Balance] = { SQL( @@ -30,16 +33,21 @@ class BalancePostgresDAO { ).as(parseBalance.singleOpt).flatten } - def getRichest(query: PaginatedQuery)(implicit conn: Connection): List[Balance] = { + def get( + query: PaginatedQuery, + ordering: FieldOrdering[BalanceField])( + implicit conn: Connection): List[Balance] = { + + val orderBy = fieldOrderingSQLInterpreter.toOrderByClause(ordering) SQL( - """ + s""" |SELECT address, received, spent, available |FROM balances |WHERE address NOT IN ( | SELECT address | FROM hidden_addresses |) - |ORDER BY available DESC + |$orderBy |OFFSET {offset} |LIMIT {limit} """.stripMargin diff --git a/server/app/com/xsn/explorer/data/async/BalanceFutureDataHandler.scala b/server/app/com/xsn/explorer/data/async/BalanceFutureDataHandler.scala index 3b10bd8..1da1bf7 100644 --- a/server/app/com/xsn/explorer/data/async/BalanceFutureDataHandler.scala +++ b/server/app/com/xsn/explorer/data/async/BalanceFutureDataHandler.scala @@ -6,7 +6,8 @@ import com.alexitc.playsonify.core.FutureApplicationResult import com.xsn.explorer.data.{BalanceBlockingDataHandler, BalanceDataHandler} import com.xsn.explorer.executors.DatabaseExecutionContext import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.base.{FieldOrdering, PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.fields.BalanceField import scala.concurrent.Future @@ -19,7 +20,7 @@ class BalanceFutureDataHandler @Inject() ( blockingDataHandler.upsert(balance) } - override def getRichest(query: PaginatedQuery): FutureApplicationResult[PaginatedResult[Balance]] = Future { - blockingDataHandler.getRichest(query) + override def get(query: PaginatedQuery, ordering: FieldOrdering[BalanceField]): FutureApplicationResult[PaginatedResult[Balance]] = Future { + blockingDataHandler.get(query, ordering) } } diff --git a/server/app/com/xsn/explorer/services/BalanceService.scala b/server/app/com/xsn/explorer/services/BalanceService.scala index 5773ea5..c6bd5bc 100644 --- a/server/app/com/xsn/explorer/services/BalanceService.scala +++ b/server/app/com/xsn/explorer/services/BalanceService.scala @@ -6,20 +6,23 @@ import com.alexitc.playsonify.core.FutureApplicationResult import com.alexitc.playsonify.core.FutureOr.Implicits.{FutureOps, OrOps} import com.xsn.explorer.data.async.BalanceFutureDataHandler import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{PaginatedQuery, PaginatedResult} +import com.xsn.explorer.models.base.{OrderingQuery, PaginatedQuery, PaginatedResult} +import com.xsn.explorer.parsers.BalanceOrderingParser import com.xsn.explorer.services.validators.PaginatedQueryValidator import scala.concurrent.ExecutionContext class BalanceService @Inject() ( paginatedQueryValidator: PaginatedQueryValidator, + balanceOrderingParser: BalanceOrderingParser, balanceFutureDataHandler: BalanceFutureDataHandler)( implicit ec: ExecutionContext) { - def getRichest(query: PaginatedQuery): FutureApplicationResult[PaginatedResult[Balance]] = { + def get(paginatedQuery: PaginatedQuery, orderingQuery: OrderingQuery): FutureApplicationResult[PaginatedResult[Balance]] = { val result = for { - validatedQuery <- paginatedQueryValidator.validate(query).toFutureOr - balances <- balanceFutureDataHandler.getRichest(validatedQuery).toFutureOr + validatedQuery <- paginatedQueryValidator.validate(paginatedQuery).toFutureOr + ordering <- balanceOrderingParser.from(orderingQuery).toFutureOr + balances <- balanceFutureDataHandler.get(validatedQuery, ordering).toFutureOr } yield balances result.toFuture diff --git a/server/app/controllers/BalancesController.scala b/server/app/controllers/BalancesController.scala index 069e971..b902dfe 100644 --- a/server/app/controllers/BalancesController.scala +++ b/server/app/controllers/BalancesController.scala @@ -2,7 +2,7 @@ package controllers import javax.inject.Inject -import com.xsn.explorer.models.base.{Limit, Offset, PaginatedQuery} +import com.xsn.explorer.models.base.{Limit, Offset, OrderingQuery, PaginatedQuery} import com.xsn.explorer.services.BalanceService import controllers.common.{MyJsonController, MyJsonControllerComponents} @@ -11,8 +11,10 @@ class BalancesController @Inject() ( cc: MyJsonControllerComponents) extends MyJsonController(cc) { - def getRichest(offset: Int, limit: Int) = publicNoInput { _ => - val query = PaginatedQuery(Offset(offset), Limit(limit)) - balanceService.getRichest(query) + def get(offset: Int, limit: Int, ordering: String) = publicNoInput { _ => + val paginatedQuery = PaginatedQuery(Offset(offset), Limit(limit)) + val orderingQuery = OrderingQuery(ordering) + + balanceService.get(paginatedQuery, orderingQuery) } } \ No newline at end of file diff --git a/server/conf/routes b/server/conf/routes index 15523b0..4f3043e 100644 --- a/server/conf/routes +++ b/server/conf/routes @@ -14,4 +14,4 @@ GET /blocks/:blockhash controllers.BlocksController.getDetails(blockhash: GET /stats controllers.StatisticsController.getStatus() -GET /balances controllers.BalancesController.getRichest(offset: Int ?= 0, limit: Int ?= 10) +GET /balances controllers.BalancesController.get(offset: Int ?= 0, limit: Int ?= 10, orderBy: String ?= "") diff --git a/server/test/com/xsn/explorer/data/BalancePostgresDataHandlerSpec.scala b/server/test/com/xsn/explorer/data/BalancePostgresDataHandlerSpec.scala index 2a7b2b1..31e0885 100644 --- a/server/test/com/xsn/explorer/data/BalancePostgresDataHandlerSpec.scala +++ b/server/test/com/xsn/explorer/data/BalancePostgresDataHandlerSpec.scala @@ -2,15 +2,19 @@ package com.xsn.explorer.data import com.xsn.explorer.data.anorm.BalancePostgresDataHandler import com.xsn.explorer.data.anorm.dao.BalancePostgresDAO +import com.xsn.explorer.data.anorm.interpreters.FieldOrderingSQLInterpreter import com.xsn.explorer.data.common.PostgresDataHandlerSpec import com.xsn.explorer.helpers.DataHelper import com.xsn.explorer.models.Balance -import com.xsn.explorer.models.base.{Limit, Offset, PaginatedQuery} +import com.xsn.explorer.models.base._ +import com.xsn.explorer.models.fields.BalanceField import org.scalactic.Good class BalancePostgresDataHandlerSpec extends PostgresDataHandlerSpec { - lazy val dataHandler = new BalancePostgresDataHandler(database, new BalancePostgresDAO) + lazy val dataHandler = new BalancePostgresDataHandler(database, new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) + + val defaultOrdering = FieldOrdering(BalanceField.Available, OrderingCondition.DescendingOrder) "upsert" should { "create an empty balance" in { @@ -49,7 +53,7 @@ class BalancePostgresDataHandlerSpec extends PostgresDataHandlerSpec { } } - "getRichest" should { + "get" should { val balances = List( Balance( @@ -86,7 +90,7 @@ class BalancePostgresDataHandlerSpec extends PostgresDataHandlerSpec { val query = PaginatedQuery(Offset(0), Limit(3)) val expected = balances.take(3) - val result = dataHandler.getRichest(query) + val result = dataHandler.get(query, defaultOrdering) result.map(_.data) mustEqual Good(expected) } @@ -95,7 +99,7 @@ class BalancePostgresDataHandlerSpec extends PostgresDataHandlerSpec { val query = PaginatedQuery(Offset(1), Limit(3)) val expected = balances.drop(1).take(3) - val result = dataHandler.getRichest(query) + val result = dataHandler.get(query, defaultOrdering) result.map(_.data) mustEqual Good(expected) } } diff --git a/server/test/com/xsn/explorer/processors/BlockEventsProcessorSpec.scala b/server/test/com/xsn/explorer/processors/BlockEventsProcessorSpec.scala index 110e3e4..2bfb538 100644 --- a/server/test/com/xsn/explorer/processors/BlockEventsProcessorSpec.scala +++ b/server/test/com/xsn/explorer/processors/BlockEventsProcessorSpec.scala @@ -1,6 +1,7 @@ package com.xsn.explorer.processors import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, BlockPostgresDAO, StatisticsPostgresDAO, TransactionPostgresDAO} +import com.xsn.explorer.data.anorm.interpreters.FieldOrderingSQLInterpreter import com.xsn.explorer.data.anorm.{BlockPostgresDataHandler, DatabasePostgresSeeder, StatisticsPostgresDataHandler} import com.xsn.explorer.data.async.{BlockFutureDataHandler, DatabaseFutureSeeder} import com.xsn.explorer.data.common.PostgresDataHandlerSpec @@ -17,7 +18,7 @@ class BlockEventsProcessorSpec extends PostgresDataHandlerSpec with ScalaFutures database, new BlockPostgresDAO, new TransactionPostgresDAO, - new BalancePostgresDAO) + new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) lazy val xsnService = new FileBasedXSNService lazy val processor = new BlockEventsProcessor( diff --git a/server/test/controllers/BalancesControllerSpec.scala b/server/test/controllers/BalancesControllerSpec.scala index fe4a104..c155e8d 100644 --- a/server/test/controllers/BalancesControllerSpec.scala +++ b/server/test/controllers/BalancesControllerSpec.scala @@ -5,6 +5,7 @@ import com.xsn.explorer.data.BalanceBlockingDataHandler import com.xsn.explorer.helpers.DataHelper import com.xsn.explorer.models.Balance import com.xsn.explorer.models.base._ +import com.xsn.explorer.models.fields.BalanceField import controllers.common.MyAPISpec import org.scalactic.Good import play.api.inject.bind @@ -40,7 +41,7 @@ class BalancesControllerSpec extends MyAPISpec { override def upsert(balance: Balance): ApplicationResult[Balance] = ??? - override def getRichest(query: PaginatedQuery): ApplicationResult[PaginatedResult[Balance]] = { + override def get(query: PaginatedQuery, ordering: FieldOrdering[BalanceField]): ApplicationResult[PaginatedResult[Balance]] = { val list = balances.drop(query.offset.int).take(query.limit.int) val result = PaginatedResult( offset = query.offset,