diff --git a/.travis.yml b/.travis.yml index d3a20af..ec3df51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: scala scala: - - 2.13.6 - - 2.12.14 + - 3.0.1 script: - sbt ++$TRAVIS_SCALA_VERSION compile test publishLocal diff --git a/CHANGELOG.md b/CHANGELOG.md index aade0c3..6d89691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ CHANGELOG ========= +3.0.0 - Add support for scala 3 + +Scala 2 +------- 0.2.0 - Upgrade sttp client 3 0.1.7 - Coingecko scala client \ No newline at end of file diff --git a/README.md b/README.md index 7453d37..d08aa64 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,12 @@ any backend that sttp supports. ## Setup with sbt Add the following dependency: +Scala 3 +```scala +"com.besselstudio.coingecko" %% "client" % "3.0.0" +``` +Scala 2, we will backport updates in the branch 2.x ```scala "com.besselstudio.coingecko" %% "client" % "0.2.0" ``` @@ -34,7 +39,7 @@ import scala.util.{Failure, Success, Try} object CoingeckoApp extends App { println(s"Coingecko App Start") - implicit lazy val backend: SttpBackend[Identity, Any] = HttpURLConnectionBackend() + given backend: SttpBackend[Identity, Any] = HttpURLConnectionBackend() lazy val api = new CoingeckoApi() lazy val client = new CoingeckoClientImpl(api) diff --git a/build.sbt b/build.sbt index 6816a93..289d167 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ import ReleaseTransformations._ -ThisBuild / scalaVersion := "2.13.6" +ThisBuild / scalaVersion := "3.0.1" ThisBuild / organization := "com.besselstudio" ThisBuild / organizationName := "Bessel Studio" ThisBuild / homepage := Some(url("https://github.com/besselstudio/coingecko")) @@ -20,7 +20,9 @@ lazy val root = (project in file(".")) "scm:git:git@github.com:besselstudio/coingecko.git" ) ), - crossScalaVersions := Seq(scalaVersion.value, "2.12.14"), + scalacOptions ++= Seq( + "-Xmax-inlines", "64" //Solves: Maximal number of successive inlines (32) exceeded + ), resolvers ++= Seq( Resolver.sonatypeRepo("releases"), Resolver.sonatypeRepo("snapshots") diff --git a/project/Dependencies.scala b/project/Dependencies.scala index df5d3a5..cc0a794 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -1,23 +1,20 @@ import sbt._ object Version { - val sttpVersion = "3.3.6" + val sttpVersion = "3.3.13" val scalaTestVersion = "3.2.9" - val playJsonVersion = "2.9.2" - val playJsonxVersion = "0.42.0" + val playJsonVersion = "2.10.0-RC5" } object Dependencies { import Version._ - lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.2.2" % Test + lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.2.9" % Test lazy val playJson = "com.typesafe.play" %% "play-json" % playJsonVersion lazy val sttpClient = "com.softwaremill.sttp.client3" %% "core" % sttpVersion - lazy val playJsonx = "ai.x" %% "play-json-extensions" % playJsonxVersion lazy val common = Seq( scalaTest, playJson, - sttpClient, - playJsonx + sttpClient ) } diff --git a/project/build.properties b/project/build.properties index 19479ba..10fd9ee 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.2 +sbt.version=1.5.5 diff --git a/src/main/scala/com/besselstudio/coingecko/CoingeckoApi.scala b/src/main/scala/com/besselstudio/coingecko/CoingeckoApi.scala index 3cb1f0f..29e337d 100644 --- a/src/main/scala/com/besselstudio/coingecko/CoingeckoApi.scala +++ b/src/main/scala/com/besselstudio/coingecko/CoingeckoApi.scala @@ -3,7 +3,7 @@ package com.besselstudio.coingecko import sttp.client3.{Identity, Response, SttpBackend, UriContext, basicRequest} import sttp.model.QueryParams -class CoingeckoApi(implicit val backend: SttpBackend[Identity, Any]) { +class CoingeckoApi(using val backend: SttpBackend[Identity, Any]) { def get(endpoint: String, params: QueryParams): Identity[Response[Either[String, String]]] = { val apiUrl = s"${CoingeckoApi.baseUrl}/$endpoint" println(uri"${apiUrl}" diff --git a/src/main/scala/com/besselstudio/coingecko/CoingeckoApiError.scala b/src/main/scala/com/besselstudio/coingecko/CoingeckoApiError.scala index d6b0af6..f15948b 100644 --- a/src/main/scala/com/besselstudio/coingecko/CoingeckoApiError.scala +++ b/src/main/scala/com/besselstudio/coingecko/CoingeckoApiError.scala @@ -1,5 +1,6 @@ package com.besselstudio.coingecko +import com.besselstudio.coingecko.model.response.BaseResponse import play.api.libs.json.{Format, Json} case class CoingeckoApiError( @@ -7,8 +8,8 @@ case class CoingeckoApiError( error: String ) -object CoingeckoApiError { - implicit lazy val format: Format[CoingeckoApiError] = Json.format[CoingeckoApiError] +object CoingeckoApiError extends BaseResponse { + given Format[CoingeckoApiError] = Json.format[CoingeckoApiError] def internalApiError(message: Option[String] = None): CoingeckoApiError = CoingeckoApiError(500, s"${message.getOrElse("Coingecko Api Error")}") diff --git a/src/main/scala/com/besselstudio/coingecko/client/CoingeckoClientImpl.scala b/src/main/scala/com/besselstudio/coingecko/client/CoingeckoClientImpl.scala index d8fc68e..1c7fcf1 100644 --- a/src/main/scala/com/besselstudio/coingecko/client/CoingeckoClientImpl.scala +++ b/src/main/scala/com/besselstudio/coingecko/client/CoingeckoClientImpl.scala @@ -1,38 +1,18 @@ package com.besselstudio.coingecko.client +import play.api.libs.json.{Format, JsError, Json, JsSuccess} import com.besselstudio.coingecko.model.coins.CoinPrice.CoinWithCurrencies -import com.besselstudio.coingecko.{ - CoingeckoApi, - CoingeckoApiError, - CoingeckoClient -} +import com.besselstudio.coingecko.{CoingeckoApi, CoingeckoApiError, CoingeckoClient} import com.besselstudio.coingecko.model.coins.status.ProjectUpdate -import com.besselstudio.coingecko.model.coins.{ - BaseCoin, - Coin, - CoinHistory, - CoinMarket, - CoinTicker, - MarketChart -} -import com.besselstudio.coingecko.model.events.{ - EventCountries, - EventTypes, - Events -} -import com.besselstudio.coingecko.model.exchanges.{ - BaseExchange, - Exchange, - ExchangeRates, - ExchangeTickers -} +import com.besselstudio.coingecko.model.coins.{BaseCoin, Coin, CoinHistory, CoinMarket, CoinTicker, MarketChart} +import com.besselstudio.coingecko.model.events.{EventCountries, EventTypes, Events} +import com.besselstudio.coingecko.model.exchanges.{BaseExchange, Exchange, ExchangeRates, ExchangeTickers} import com.besselstudio.coingecko.model.global.Global import com.besselstudio.coingecko.model.response.PingResponse -import play.api.libs.json.{JsError, JsSuccess, Json, Reads} import sttp.model.QueryParams class CoingeckoClientImpl( - api: CoingeckoApi + api: CoingeckoApi ) extends CoingeckoClient { override def ping: Either[CoingeckoApiError, PingResponse] = @@ -237,6 +217,7 @@ class CoingeckoClientImpl( ): Either[CoingeckoApiError, CoinHistory] = { def buildQuery = Map( + "date" -> Some(date), "localization" -> localization.map(_.toString) ).filter(kv => kv._2.nonEmpty) .map(kv => kv._1 -> kv._2.getOrElse("")) @@ -474,8 +455,8 @@ class CoingeckoClientImpl( override def getGlobal: Either[CoingeckoApiError, Global] = get[Global](endpoint = "global", QueryParams()) - def get[T](endpoint: String, queryParams: QueryParams)( - implicit reads: Reads[T] + protected def get[T](endpoint: String, queryParams: QueryParams)( + using Format[T] ): Either[CoingeckoApiError, T] = api.get(endpoint, queryParams).body match { case Left(json) => @@ -487,7 +468,8 @@ class CoingeckoClientImpl( case Right(json) => Json.parse(json).validate[T] match { - case JsSuccess(value, _) => Right(value) + case JsSuccess(value, _) => + Right(value) case JsError(errors) => Left( CoingeckoApiError diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/BaseCoin.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/BaseCoin.scala index c0e0ce9..98e3616 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/BaseCoin.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/BaseCoin.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.coins import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class BaseCoin( id: String, @@ -9,6 +9,6 @@ case class BaseCoin( name: String ) -object BaseCoin extends BaseResponse{ - implicit val baseCoinReads: Reads[BaseCoin] = Json.reads[BaseCoin] +object BaseCoin extends BaseResponse { + given Format[BaseCoin] = Json.format[BaseCoin] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/Coin.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/Coin.scala index fa3c9a5..e897ce1 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/Coin.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/Coin.scala @@ -8,5 +8,5 @@ case class Coin( ) object Coin extends BaseResponse { - implicit val format: Format[Coin] = Json.format[Coin] + given Format[Coin] = Json.format[Coin] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinHistory.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinHistory.scala index a27f1d0..5c74acc 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinHistory.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinHistory.scala @@ -11,12 +11,12 @@ case class CoinHistory( name: String, localization: Map[String, String], image: Image, - marketData: MarketData, - communityData: CommunityData, - developerData: DeveloperData, - publicInterestStats: PublicInterestStats + marketData: Option[MarketData], + communityData: Option[CommunityData], + developerData: Option[DeveloperData], + publicInterestStats: Option[PublicInterestStats] ) object CoinHistory extends BaseResponse { - implicit val format: Format[CoinHistory] = Json.format[CoinHistory] + given Format[CoinHistory] = Json.format[CoinHistory] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinMarket.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinMarket.scala index c0938ff..5a7b809 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinMarket.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinMarket.scala @@ -2,7 +2,7 @@ package com.besselstudio.coingecko.model.coins import com.besselstudio.coingecko.model.coins.data.Roi import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class CoinMarket( id: String, @@ -30,5 +30,5 @@ case class CoinMarket( ) object CoinMarket extends BaseResponse { - implicit val coinMarketReads: Reads[CoinMarket] = Json.reads[CoinMarket] + given Format[CoinMarket] = Json.format[CoinMarket] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinTicker.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinTicker.scala index 6a29840..0a7cb28 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/CoinTicker.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/CoinTicker.scala @@ -1,13 +1,14 @@ package com.besselstudio.coingecko.model.coins import com.besselstudio.coingecko.model.coins.common.Ticker -import play.api.libs.json.{Json, Reads} +import com.besselstudio.coingecko.model.response.BaseResponse +import play.api.libs.json.{Format, Json} case class CoinTicker( name: String, tickers: List[Ticker] ) -object CoinTicker { - implicit val reads: Reads[CoinTicker] = Json.reads[CoinTicker] +object CoinTicker extends BaseResponse { + given Format[CoinTicker] = Json.format[CoinTicker] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/MarketChart.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/MarketChart.scala index f050cc8..381a3a4 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/MarketChart.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/MarketChart.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.coins import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class MarketChart( prices: List[List[String]], @@ -10,5 +10,5 @@ case class MarketChart( ) object MarketChart extends BaseResponse { - implicit val reads: Reads[MarketChart] = Json.reads[MarketChart] + given Format[MarketChart] = Json.format[MarketChart] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Image.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Image.scala index cdaa1c3..83eb6db 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Image.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Image.scala @@ -4,11 +4,11 @@ import com.besselstudio.coingecko.model.response.BaseResponse import play.api.libs.json.{Format, Json} case class Image( - thumb: String, - small: String, - large: String + thumb: Option[String], + small: Option[String], + large: Option[String] ) object Image extends BaseResponse { - implicit val format: Format[Image] = Json.format[Image] + given Format[Image] = Json.format[Image] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Market.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Market.scala index a488643..517badd 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Market.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Market.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.coins.common import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Format} +import play.api.libs.json.{Format, Json} case class Market( name: String, @@ -10,5 +10,5 @@ case class Market( ) object Market extends BaseResponse { - implicit val format: Format[Market] = Json.format[Market] + given Format[Market] = Json.format[Market] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Ticker.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Ticker.scala index a42b78f..1eb0eb1 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/common/Ticker.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/common/Ticker.scala @@ -23,6 +23,6 @@ case class Ticker( ) object Ticker extends BaseResponse { - implicit val format: Format[Ticker] = Json.format[Ticker] + given Format[Ticker] = Json.format[Ticker] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/CodeAdditionsDeletions4Weeks.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/CodeAdditionsDeletions4Weeks.scala index 3a8f419..310d545 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/CodeAdditionsDeletions4Weeks.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/CodeAdditionsDeletions4Weeks.scala @@ -9,5 +9,5 @@ case class CodeAdditionsDeletions4Weeks( ) object CodeAdditionsDeletions4Weeks extends BaseResponse { - implicit val format: Format[CodeAdditionsDeletions4Weeks] = Json.format[CodeAdditionsDeletions4Weeks] + given Format[CodeAdditionsDeletions4Weeks] = Json.format[CodeAdditionsDeletions4Weeks] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/CommunityData.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/CommunityData.scala index 55d95c6..23bfddf 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/CommunityData.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/CommunityData.scala @@ -4,15 +4,15 @@ import com.besselstudio.coingecko.model.response.BaseResponse import play.api.libs.json.{Format, Json} case class CommunityData( - facebookLikes: Double, - twitterFollowers: Double, - redditAveragePosts48h: Double, - redditAverageComments48h: Double, - redditSubscribers: Double, - redditAccountsActive48h: Double, - telegramChannelUserCount: Double + facebookLikes: Option[Double], + twitterFollowers: Option[Double], + redditAveragePosts48h: Option[Double], + redditAverageComments48h: Option[Double], + redditSubscribers: Option[Double], + redditAccountsActive48h: Option[Double], + telegramChannelUserCount: Option[Double] ) object CommunityData extends BaseResponse { - implicit val format: Format[CommunityData] = Json.format[CommunityData] + given Format[CommunityData] = Json.format[CommunityData] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/DeveloperData.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/DeveloperData.scala index e1dde22..a567cb2 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/DeveloperData.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/DeveloperData.scala @@ -6,16 +6,16 @@ import play.api.libs.json.{Format, Json} case class DeveloperData( forks: Long, stars: Long, - subscribers: Long, - totalIssues: Long, - closedIssues: Long, - pullRequestsMerged: Long, - pullRequestContributors: Long, - codeAdditionsDeletions4Weeks: CodeAdditionsDeletions4Weeks, - commitCount4Weeks: Long, - last4WeeksCommitActivitySeries: List[Long] + subscribers: Option[Long], + totalIssues: Option[Long], + closedIssues: Option[Long], + pullRequestsMerged: Option[Long], + pullRequestContributors: Option[Long], + codeAdditionsDeletions4Weeks: Option[CodeAdditionsDeletions4Weeks], + commitCount4Weeks: Option[Long], + last4WeeksCommitActivitySeries: Option[List[Long]] ) object DeveloperData extends BaseResponse { - implicit val format: Format[DeveloperData] = Json.format[DeveloperData] + given Format[DeveloperData] = Json.format[DeveloperData] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/MarketData.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/MarketData.scala index affd0b0..fa277b2 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/MarketData.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/MarketData.scala @@ -1,44 +1,42 @@ package com.besselstudio.coingecko.model.coins.data -import ai.x.play.json.{CamelToSnakeNameEncoder, Jsonx, NameEncoder} import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, OFormat} +import play.api.libs.json.{Format, Json} case class MarketData( currentPrice: Map[String, Double], - roi: Roi, - ath: Map[String, Double], - athChangePercentage: Map[String, Double], - athDate: Map[String, String], - marketCap: Map[String, Double], - marketCapRank: Long, - totalVolume: Map[String, Double], - priceChangePercentage24h: Double, - priceChangePercentage7d: Double, - priceChangePercentage14d: Double, - priceChangePercentage30d: Double, - priceChangePercentage60d: Double, - priceChangePercentage200d: Double, - priceChangePercentage1y: Double, - marketCapChange24h: Double, - marketCapChangePercentage24h: Double, - priceChange24hInCurrency: Map[String, Double], - priceChangePercentage1hInCurrency: Map[String, Double], - priceChangePercentage24hInCurrency: Map[String, Double], - priceChangePercentage7dInCurrency: Map[String, Double], - priceChangePercentage14dInCurrency: Map[String, Double], - priceChangePercentage30dInCurrency: Map[String, Double], - priceChangePercentage60dInCurrency: Map[String, Double], - priceChangePercentage200dInCurrency: Map[String, Double], - priceChangePercentage1yInCurrency: Map[String, Double], - marketCapChange24hInCurrency: Map[String, Double], - marketCapChangePercentage24hInCurrency: Map[String, Double], - totalSupply: Long, - circulatingSupply: Double, - lastUpdated: String + roi: Option[Roi], + ath: Option[Map[String, Double]], + athChangePercentage: Option[Map[String, Double]], + athDate: Option[Map[String, String]], + marketCap: Option[Map[String, Double]], + marketCapRank: Option[Long], + totalVolume: Option[Map[String, Double]], + priceChangePercentage24h: Option[Double], + priceChangePercentage7d: Option[Double], + priceChangePercentage14d: Option[Double], + priceChangePercentage30d: Option[Double], + priceChangePercentage60d: Option[Double], + priceChangePercentage200d: Option[Double], + priceChangePercentage1y: Option[Double], + marketCapChange24h: Option[Double], + marketCapChangePercentage24h: Option[Double], + priceChange24hInCurrency: Option[Map[String, Double]], + priceChangePercentage1hInCurrency: Option[Map[String, Double]], + priceChangePercentage24hInCurrency: Option[Map[String, Double]], + priceChangePercentage7dInCurrency: Option[Map[String, Double]], + priceChangePercentage14dInCurrency: Option[Map[String, Double]], + priceChangePercentage30dInCurrency: Option[Map[String, Double]], + priceChangePercentage60dInCurrency: Option[Map[String, Double]], + priceChangePercentage200dInCurrency: Option[Map[String, Double]], + priceChangePercentage1yInCurrency: Option[Map[String, Double]], + marketCapChange24hInCurrency: Option[Map[String, Double]], + marketCapChangePercentage24hInCurrency: Option[Map[String, Double]], + totalSupply: Option[Long], + circulatingSupply: Option[Double], + lastUpdated: Option[String] ) object MarketData extends BaseResponse { - implicit val encoder: NameEncoder = CamelToSnakeNameEncoder() - implicit lazy val format: OFormat[MarketData] = Jsonx.formatCaseClass[MarketData] + given Format[MarketData] = Json.format[MarketData] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/PublicInterestStats.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/PublicInterestStats.scala index 99e6864..ff34381 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/PublicInterestStats.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/PublicInterestStats.scala @@ -1,13 +1,13 @@ package com.besselstudio.coingecko.model.coins.data import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Format, Json, Reads} +import play.api.libs.json.{Format, Json} case class PublicInterestStats( - alexaRank: Long, - bingMatches: Long + alexaRank: Option[Long], + bingMatches: Option[Long] ) object PublicInterestStats extends BaseResponse { - implicit val format: Format[PublicInterestStats] = Json.format[PublicInterestStats] + given Format[PublicInterestStats] = Json.format[PublicInterestStats] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/data/Roi.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/data/Roi.scala index 9c02a1f..be35fac 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/data/Roi.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/data/Roi.scala @@ -10,5 +10,5 @@ case class Roi( ) object Roi extends BaseResponse { - implicit val format: Format[Roi] = Json.format[Roi] + given Format[Roi] = Json.format[Roi] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/status/Project.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/status/Project.scala index f4fa670..106aa78 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/status/Project.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/status/Project.scala @@ -1,6 +1,7 @@ package com.besselstudio.coingecko.model.coins.status import com.besselstudio.coingecko.model.coins.common.Image +import com.besselstudio.coingecko.model.response.BaseResponse import play.api.libs.json.{Format, Json} case class Project( @@ -11,6 +12,6 @@ case class Project( image: Image ) -object Project { - implicit val format: Format[Project] = Json.format[Project] +object Project extends BaseResponse { + given Format[Project] = Json.format[Project] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/coins/status/ProjectUpdate.scala b/src/main/scala/com/besselstudio/coingecko/model/coins/status/ProjectUpdate.scala index 56e0596..cc332ca 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/coins/status/ProjectUpdate.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/coins/status/ProjectUpdate.scala @@ -1,5 +1,6 @@ package com.besselstudio.coingecko.model.coins.status +import com.besselstudio.coingecko.model.response.BaseResponse import play.api.libs.json.{Format, Json} case class ProjectUpdate( @@ -12,6 +13,6 @@ case class ProjectUpdate( project: Project ) -object ProjectUpdate { - implicit val format: Format[ProjectUpdate] = Json.format[ProjectUpdate] +object ProjectUpdate extends BaseResponse { + given Format[ProjectUpdate] = Json.format[ProjectUpdate] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/events/EventCountries.scala b/src/main/scala/com/besselstudio/coingecko/model/events/EventCountries.scala index 31c31bb..581bf59 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/events/EventCountries.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/events/EventCountries.scala @@ -9,5 +9,5 @@ case class EventCountries( ) object EventCountries extends BaseResponse { - implicit val format: Format[EventCountries] = Json.format[EventCountries] + given Format[EventCountries] = Json.format[EventCountries] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/events/EventCountryData.scala b/src/main/scala/com/besselstudio/coingecko/model/events/EventCountryData.scala index 0304f49..0d812fc 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/events/EventCountryData.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/events/EventCountryData.scala @@ -9,5 +9,5 @@ case class EventCountryData( ) object EventCountryData extends BaseResponse { - implicit val format: Format[EventCountryData] = Json.format[EventCountryData] + given Format[EventCountryData] = Json.format[EventCountryData] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/events/EventData.scala b/src/main/scala/com/besselstudio/coingecko/model/events/EventData.scala index d7b8202..5ee4ae3 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/events/EventData.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/events/EventData.scala @@ -20,5 +20,5 @@ case class EventData( ) object EventData extends BaseResponse { - implicit val format: Format[EventData] = Json.format[EventData] + given Format[EventData] = Json.format[EventData] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/events/EventTypes.scala b/src/main/scala/com/besselstudio/coingecko/model/events/EventTypes.scala index 107c59b..32336de 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/events/EventTypes.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/events/EventTypes.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.events import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class EventTypes( data: List[String], @@ -9,5 +9,5 @@ case class EventTypes( ) object EventTypes extends BaseResponse { - implicit val reads: Reads[EventTypes] = Json.reads[EventTypes] + given Format[EventTypes] = Json.format[EventTypes] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/events/Events.scala b/src/main/scala/com/besselstudio/coingecko/model/events/Events.scala index a19ae66..ef93acc 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/events/Events.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/events/Events.scala @@ -9,6 +9,6 @@ case class Events( page: Long ) -object Events extends BaseResponse { - implicit val format: Format[Events] = Json.format[Events] +object Events extends BaseResponse { + given Format[Events] = Json.format[Events] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/exchanges/BaseExchange.scala b/src/main/scala/com/besselstudio/coingecko/model/exchanges/BaseExchange.scala index 6fd76b8..af2791e 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/exchanges/BaseExchange.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/exchanges/BaseExchange.scala @@ -9,5 +9,5 @@ case class BaseExchange( ) object BaseExchange extends BaseResponse { - implicit val format: Format[BaseExchange] = Json.format[BaseExchange] + given Format[BaseExchange] = Json.format[BaseExchange] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/exchanges/Exchange.scala b/src/main/scala/com/besselstudio/coingecko/model/exchanges/Exchange.scala index 7c73624..0a9369c 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/exchanges/Exchange.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/exchanges/Exchange.scala @@ -1,8 +1,7 @@ package com.besselstudio.coingecko.model.exchanges import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.OFormat -import ai.x.play.json.{CamelToSnakeNameEncoder, Jsonx, NameEncoder} +import play.api.libs.json.{Format, Json} case class Exchange( id: String, @@ -31,6 +30,5 @@ case class Exchange( ) object Exchange extends BaseResponse { - implicit val encoder: NameEncoder = CamelToSnakeNameEncoder() - implicit lazy val format: OFormat[Exchange] = Jsonx.formatCaseClass[Exchange] + given Format[Exchange] = Json.format[Exchange] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeRates.scala b/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeRates.scala index d5bcfb5..dcfb1af 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeRates.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeRates.scala @@ -1,12 +1,12 @@ package com.besselstudio.coingecko.model.exchanges import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class ExchangeRates( rates: Map[String, Rate] ) object ExchangeRates extends BaseResponse { - implicit val reads: Reads[ExchangeRates] = Json.reads[ExchangeRates] + given Format[ExchangeRates] = Json.format[ExchangeRates] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeTickers.scala b/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeTickers.scala index 8973c3a..fe04289 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeTickers.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/exchanges/ExchangeTickers.scala @@ -11,5 +11,5 @@ case class ExchangeTickers( object ExchangeTickers extends BaseResponse { - implicit val format: Format[ExchangeTickers] = Json.format[ExchangeTickers] + given Format[ExchangeTickers] = Json.format[ExchangeTickers] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/exchanges/Rate.scala b/src/main/scala/com/besselstudio/coingecko/model/exchanges/Rate.scala index d28b0b5..9f45128 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/exchanges/Rate.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/exchanges/Rate.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.exchanges import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class Rate( name: String, @@ -11,5 +11,5 @@ case class Rate( ) object Rate extends BaseResponse { - implicit val reads: Reads[Rate] = Json.reads[Rate] + given Format[Rate] = Json.format[Rate] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/global/Global.scala b/src/main/scala/com/besselstudio/coingecko/model/global/Global.scala index 3f21c9c..43850d8 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/global/Global.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/global/Global.scala @@ -1,12 +1,12 @@ package com.besselstudio.coingecko.model.global import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class Global( global: Globaldata ) object Global extends BaseResponse { - implicit val reads: Reads[Global] = Json.reads[Global] + given Format[Global] = Json.format[Global] } \ No newline at end of file diff --git a/src/main/scala/com/besselstudio/coingecko/model/global/Globaldata.scala b/src/main/scala/com/besselstudio/coingecko/model/global/Globaldata.scala index fce512d..0d03b5d 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/global/Globaldata.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/global/Globaldata.scala @@ -1,7 +1,7 @@ package com.besselstudio.coingecko.model.global import com.besselstudio.coingecko.model.response.BaseResponse -import play.api.libs.json.{Json, Reads} +import play.api.libs.json.{Format, Json} case class Globaldata( activeCryptocurrencies: Long, @@ -17,5 +17,5 @@ case class Globaldata( ) object Globaldata extends BaseResponse { - implicit val reads: Reads[Globaldata] = Json.reads[Globaldata] + given Format[Globaldata] = Json.format[Globaldata] } diff --git a/src/main/scala/com/besselstudio/coingecko/model/response/BaseResponse.scala b/src/main/scala/com/besselstudio/coingecko/model/response/BaseResponse.scala index ec7fd26..cc2cfaa 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/response/BaseResponse.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/response/BaseResponse.scala @@ -1,9 +1,8 @@ package com.besselstudio.coingecko.model.response -import play.api.libs.json.{Json, JsonConfiguration} -import play.api.libs.json.JsonConfiguration.Aux +import play.api.libs.json.{JsonConfiguration, Json} import play.api.libs.json.JsonNaming.SnakeCase trait BaseResponse { - implicit val config: Aux[Json.MacroOptions] = JsonConfiguration(SnakeCase) + given JsonConfiguration.Aux[Json.WithDefaultValues] = JsonConfiguration[Json.WithDefaultValues](naming = SnakeCase) } diff --git a/src/main/scala/com/besselstudio/coingecko/model/response/PingResponse.scala b/src/main/scala/com/besselstudio/coingecko/model/response/PingResponse.scala index 136d128..c2debd5 100644 --- a/src/main/scala/com/besselstudio/coingecko/model/response/PingResponse.scala +++ b/src/main/scala/com/besselstudio/coingecko/model/response/PingResponse.scala @@ -1,13 +1,13 @@ package com.besselstudio.coingecko.model.response -import play.api.libs.json._ +import play.api.libs.json.{Format, Json} case class PingResponse( geckoSays: String ) object PingResponse extends BaseResponse { - implicit val pingReads: Reads[PingResponse] = Json.reads[PingResponse] + given Format[PingResponse] = Json.format[PingResponse] } diff --git a/src/test/scala/com/besselstudio/coingecko/examples/CoingeckoApp.scala b/src/test/scala/com/besselstudio/coingecko/examples/CoingeckoApp.scala index 2759861..fe68374 100644 --- a/src/test/scala/com/besselstudio/coingecko/examples/CoingeckoApp.scala +++ b/src/test/scala/com/besselstudio/coingecko/examples/CoingeckoApp.scala @@ -8,34 +8,58 @@ import scala.util.{Failure, Success, Try} object CoingeckoApp extends App { println(s"Coingecko App Start") - implicit lazy val backend: SttpBackend[Identity, Any] = HttpURLConnectionBackend() + given SttpBackend[Identity, Any] = HttpURLConnectionBackend() lazy val api = new CoingeckoApi() lazy val client = new CoingeckoClientImpl(api) - Try { - client.ping - } match { - case Success(value) => - value match { - case Left(_) => println(s"Ping Failed") - case Right(response) => println(s"${response.geckoSays}") - } - case Failure(exception) => - println(s"Failure ${exception.getMessage}") - } - - Try { - client.getPrice(List("bitcoin"), List("eth", "usd")) - } match { - case Success(value) => - value match { - case Left(c) => println(s"List Price failed ${c.code} reason ${c.error}") - case Right(priceWithCurrencies) => println(s"Price BTC ${priceWithCurrencies("bitcoin").mkString(",")}") - } - case Failure(exception) => - println(s"Failure ${exception.getMessage}") - } + Try { + client.ping + } match { + case Success(value) => + value match { + case Left(_) => println(s"Ping Failed") + case Right(response) => println(s"${response.geckoSays}") + } + case Failure(exception) => + println(s"Failure ${exception.getMessage}") + } + + Try { + client.getPrice(List("bitcoin"), List("eth", "usd")) + } match { + case Success(value) => + value match { + case Left(c) => println(s"List Price failed ${c.code} reason ${c.error}") + case Right(priceWithCurrencies) => println(s"Price BTC ${priceWithCurrencies("bitcoin").mkString(",")}") + } + case Failure(exception) => + println(s"Failure ${exception.getMessage}") + } + + Try { + client.getCoinsList + } match { + case Success(payload) => + payload match { + case Left(apiError) => println(s"Coins list failed ${apiError.code} reason ${apiError.error}") + case Right(coins) => println(s"Coins List total ${coins.length} first 20 \n ${coins.filter(_.id.length < 10).slice(30, 50).map(_.id).mkString("\n")}") + } + case Failure(exception) => + println(s"Failure ${exception.getMessage}") + } + + Try { + client.getCoinHistoryById("aave", "30-12-2020") + } match { + case Success(response) => + response match { + case Left(error) => print(s"api call failed ${error.code} reason ${error.error}") + case Right(history) => println(s"Coin History circulating supply: ${history.marketData.flatMap(_.circulatingSupply).getOrElse("N/A")}") + } + case Failure(exception) => + println(s"Failure ${exception.getMessage}") + } println(s"Coingecko App End") } diff --git a/version.sbt b/version.sbt index cfeb331..652b032 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "0.2.1-SNAPSHOT" +ThisBuild / version := "3.0.0-SNAPSHOT"