diff --git a/server/app/com/xsn/explorer/models/Address.scala b/server/app/com/xsn/explorer/models/Address.scala index 8cac14a..1edac2c 100644 --- a/server/app/com/xsn/explorer/models/Address.scala +++ b/server/app/com/xsn/explorer/models/Address.scala @@ -1,8 +1,9 @@ package com.xsn.explorer.models +import com.xsn.explorer.models.base.WrappedString import play.api.libs.json._ -class Address private (val string: String) extends AnyVal +class Address private (val string: String) extends AnyVal with WrappedString object Address { @@ -25,8 +26,4 @@ object Address { } } } - - implicit val writes: Writes[Address] = Writes { obj => - JsString(obj.string) - } } diff --git a/server/app/com/xsn/explorer/models/Blockhash.scala b/server/app/com/xsn/explorer/models/Blockhash.scala index eb08f81..afa1618 100644 --- a/server/app/com/xsn/explorer/models/Blockhash.scala +++ b/server/app/com/xsn/explorer/models/Blockhash.scala @@ -1,8 +1,9 @@ package com.xsn.explorer.models +import com.xsn.explorer.models.base.WrappedString import play.api.libs.json._ -class Blockhash private (val string: String) extends AnyVal +class Blockhash private (val string: String) extends AnyVal with WrappedString object Blockhash { private val pattern = "^[a-f0-9]{64}$".r.pattern @@ -26,6 +27,4 @@ object Blockhash { } } } - - implicit val writes: Writes[Blockhash] = Writes { obj => JsString(obj.string) } } diff --git a/server/app/com/xsn/explorer/models/Confirmations.scala b/server/app/com/xsn/explorer/models/Confirmations.scala new file mode 100644 index 0000000..d56b281 --- /dev/null +++ b/server/app/com/xsn/explorer/models/Confirmations.scala @@ -0,0 +1,11 @@ +package com.xsn.explorer.models + +import com.xsn.explorer.models.base.WrappedInt +import play.api.libs.json.{JsPath, Reads} + +case class Confirmations(int: Int) extends AnyVal with WrappedInt + +object Confirmations { + + implicit val reads: Reads[Confirmations] = JsPath.read[Int].map(Confirmations.apply) +} diff --git a/server/app/com/xsn/explorer/models/Size.scala b/server/app/com/xsn/explorer/models/Size.scala new file mode 100644 index 0000000..bd208fc --- /dev/null +++ b/server/app/com/xsn/explorer/models/Size.scala @@ -0,0 +1,11 @@ +package com.xsn.explorer.models + +import com.xsn.explorer.models.base.WrappedInt +import play.api.libs.json.{JsPath, Reads} + +case class Size(int: Int) extends AnyVal with WrappedInt + +object Size { + + implicit val reads: Reads[Size] = JsPath.read[Int].map(Size.apply) +} diff --git a/server/app/com/xsn/explorer/models/Transaction.scala b/server/app/com/xsn/explorer/models/Transaction.scala index eaa88f0..62c8993 100644 --- a/server/app/com/xsn/explorer/models/Transaction.scala +++ b/server/app/com/xsn/explorer/models/Transaction.scala @@ -5,11 +5,11 @@ import play.api.libs.json._ case class Transaction( id: TransactionId, - size: Int, + size: Size, blockhash: Blockhash, time: Long, blocktime: Long, - confirmations: Int, + confirmations: Confirmations, vin: Option[TransactionVIN], vout: List[TransactionVOUT], ) @@ -18,11 +18,11 @@ object Transaction { implicit val reads: Reads[Transaction] = { val builder = (__ \ 'txid).read[TransactionId] and - (__ \ 'size).read[Int] and + (__ \ 'size).read[Size] and (__ \ 'blockhash).read[Blockhash] and (__ \ 'time).read[Long] and (__ \ 'blocktime).read[Long] and - (__ \ 'confirmations).read[Int] and + (__ \ 'confirmations).read[Confirmations] and (__ \ 'vout).read[List[TransactionVOUT]] and (__ \ 'vin).readNullable[List[JsValue]] .map(_ getOrElse List.empty) diff --git a/server/app/com/xsn/explorer/models/TransactionDetails.scala b/server/app/com/xsn/explorer/models/TransactionDetails.scala index 0fa1242..ce2dac3 100644 --- a/server/app/com/xsn/explorer/models/TransactionDetails.scala +++ b/server/app/com/xsn/explorer/models/TransactionDetails.scala @@ -4,11 +4,11 @@ import play.api.libs.json.{Json, Writes} case class TransactionDetails( id: TransactionId, - size: Int, + size: Size, blockhash: Blockhash, time: Long, blocktime: Long, - confirmations: Int, + confirmations: Confirmations, input: Option[TransactionValue], output: List[TransactionValue]) { diff --git a/server/app/com/xsn/explorer/models/TransactionId.scala b/server/app/com/xsn/explorer/models/TransactionId.scala index e1bcfef..dda90f9 100644 --- a/server/app/com/xsn/explorer/models/TransactionId.scala +++ b/server/app/com/xsn/explorer/models/TransactionId.scala @@ -1,8 +1,9 @@ package com.xsn.explorer.models +import com.xsn.explorer.models.base.WrappedString import play.api.libs.json._ -class TransactionId private (val string: String) extends AnyVal +class TransactionId private (val string: String) extends AnyVal with WrappedString object TransactionId { @@ -27,6 +28,4 @@ object TransactionId { } } } - - implicit val writes: Writes[TransactionId] = Writes { obj => JsString(obj.string) } } diff --git a/server/app/com/xsn/explorer/models/base/WrappedInt.scala b/server/app/com/xsn/explorer/models/base/WrappedInt.scala new file mode 100644 index 0000000..7719845 --- /dev/null +++ b/server/app/com/xsn/explorer/models/base/WrappedInt.scala @@ -0,0 +1,14 @@ +package com.xsn.explorer.models.base + +import play.api.libs.json.{JsNumber, Writes} + +trait WrappedInt extends Any { + def int: Int +} + +object WrappedInt { + + implicit val writes: Writes[WrappedInt] = { + Writes[WrappedInt] { wrapped => JsNumber(wrapped.int) } + } +} diff --git a/server/app/com/xsn/explorer/models/base/WrappedString.scala b/server/app/com/xsn/explorer/models/base/WrappedString.scala new file mode 100644 index 0000000..5ac6839 --- /dev/null +++ b/server/app/com/xsn/explorer/models/base/WrappedString.scala @@ -0,0 +1,14 @@ +package com.xsn.explorer.models.base + +import play.api.libs.json.{JsString, Writes} + +trait WrappedString extends Any { + def string: String +} + +object WrappedString { + + implicit val writes: Writes[WrappedString] = { + Writes[WrappedString] { wrapped => JsString(wrapped.string) } + } +} diff --git a/server/test/controllers/TransactionsControllerSpec.scala b/server/test/controllers/TransactionsControllerSpec.scala index 1b5c292..709f7c9 100644 --- a/server/test/controllers/TransactionsControllerSpec.scala +++ b/server/test/controllers/TransactionsControllerSpec.scala @@ -18,11 +18,11 @@ class TransactionsControllerSpec extends MyAPISpec { val coinbaseTx: Transaction = Transaction( id = TransactionId.from("024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c").get, - size = 98, + size = Size(98), blockhash = Blockhash.from("000003fb382f6892ae96594b81aa916a8923c70701de4e7054aac556c7271ef7").get, time = 1520276270L, blocktime = 1520276270L, - confirmations = 5347, + confirmations = Confirmations(5347), vin = None, vout = List( TransactionVOUT(n = 0, address = Address.from("XdJnCKYNwzCz8ATv8Eu75gonaHyfr9qXg9"), value = 0, scriptPubKeyType = "pubkey")) @@ -30,11 +30,11 @@ class TransactionsControllerSpec extends MyAPISpec { val nonCoinbaseTx: Transaction = Transaction( id = TransactionId.from("0834641a7d30d8a2d2b451617599670445ee94ed7736e146c13be260c576c641").get, - size = 234, + size = Size(234), blockhash = Blockhash.from("b72dd1655408e9307ef5874be20422ee71029333283e2360975bc6073bdb2b81").get, time = 1520318120, blocktime = 1520318120, - confirmations = 1950, + confirmations = Confirmations(1950), vin = Some( TransactionVIN(TransactionId.from("585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9").get, 2)), vout = List( @@ -44,11 +44,11 @@ class TransactionsControllerSpec extends MyAPISpec { val nonCoinbasePreviousTx: Transaction = Transaction( id = TransactionId.from("585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9").get, - size = 235, + size = Size(235), blockhash = Blockhash.from("cc4ccf19cfb9fa373ba8da68c7d25266d675a2414db603edb3cc88f866a782ea").get, time = 1520314409, blocktime = 1520314409, - confirmations = 11239, + confirmations = Confirmations(11239), vin = Some( TransactionVIN(TransactionId.from("fd74206866fc4ed986d39084eb9f20de6cb324b028693f33d60897ac995fff4f").get, 2)), vout = List( @@ -89,10 +89,10 @@ class TransactionsControllerSpec extends MyAPISpec { val json = contentAsJson(response) (json \ "id").as[String] mustEqual tx.id.string (json \ "blockhash").as[String] mustEqual tx.blockhash.string - (json \ "size").as[Int] mustEqual tx.size + (json \ "size").as[Size] mustEqual tx.size (json \ "time").as[Long] mustEqual tx.time (json \ "blocktime").as[Long] mustEqual tx.blocktime - (json \ "confirmations").as[Int] mustEqual tx.confirmations + (json \ "confirmations").as[Confirmations] mustEqual tx.confirmations val outputJsonList = (json \ "output").as[List[JsValue]] outputJsonList.size mustEqual 1 @@ -111,10 +111,10 @@ class TransactionsControllerSpec extends MyAPISpec { val json = contentAsJson(response) (json \ "id").as[String] mustEqual tx.id.string (json \ "blockhash").as[String] mustEqual tx.blockhash.string - (json \ "size").as[Int] mustEqual tx.size + (json \ "size").as[Size] mustEqual tx.size (json \ "time").as[Long] mustEqual tx.time (json \ "blocktime").as[Long] mustEqual tx.blocktime - (json \ "confirmations").as[Int] mustEqual tx.confirmations + (json \ "confirmations").as[Confirmations] mustEqual tx.confirmations val inputJson = (json \ "input").as[JsValue] (inputJson \ "address").as[String] mustEqual details.input.get.address.string