Home > Enterprise >  Scala compilation fails with: Could not find implicit value for parameter W
Scala compilation fails with: Could not find implicit value for parameter W

Time:11-02

I got a doobie query that doesn't want to compile:

package de.x.vmdbplanningvalues.impl.queries

import de.x.campaignplans.CampaignPlanId
import de.x.distributionbrands.DistributionBrandId
import de.x.vmdbplanningvalues._
import doobie._

object UpdateVmdbPlanningValuesQuery {
  case class VmdbPlanningUpdate(
      creditRatingRejections: Option[Double],
      goodsCoupons: Option[Double],
      customerDiscounts: Option[Double],
      campaignPlanId: String,
      distributionBrandId: String,
      country: String,
      categoryId: String,
      lane: VmdbLane
  )

  def apply(
      distributionBrand: DistributionBrandId,
      country: String,
      campaignPlanId: CampaignPlanId,
      category: String,
      updates: List[VmdbPlanningValuesForVmdbLane]
  ): ConnectionIO[Unit] = {
    for {
      _ <- updateQuery(updates.map(update =>
        VmdbPlanningUpdate(
          update.creditRatingRejections,
          update.goodsCoupons,
          update.customerDiscounts,
          campaignPlanId.id,
          distributionBrand.id,
          country,
          category,
          update.lane
        )
      ))
    } yield ()
  }

  def updateQuery[T: Write](updates: List[VmdbPlanningUpdate]): ConnectionIO[Int] = {
    val sql =
      """
         UPDATE vmdb_planning_values as vmdb
         SET vmdb.credit_rating_rejections = ?,
             vmdb.goods_coupons = ?,
             vmdb.customer_discounts = ?
         FROM campaign_plan cp
         WHERE cp.id = ?
            AND vmdb.distribution_brand_id = ?
            AND vmdb.country_id = ?
            AND vmdb.year=DATE_PART('year', cp.start_date)
            AND vmdb.quarter=DATE_PART('quarter', cp.start_date)
            AND vmdb.category_id = ?
            AND vmdb.lane = ?
      """

    Update[VmdbPlanningUpdate](sql).updateMany(updates)
  }
}

However it fails with the following error:

[error] /Users/johannesklauss/Documents/campaign-service/server/src/main/scala/de/x/vmdbplanningvalues/impl/queries/UpdateVmdbPlanningValuesQuery.scala:60:35: could not find implicit value for parameter W: doobie.Write[de.x.vmdbplanningvalues.impl.queries.UpdateVmdbPlanningValuesQuery.VmdbPlanningUpdate]
[error]     Update[VmdbPlanningUpdate](sql).updateMany(updates)
[error] 

I am not quite sure what the error message means, since I am still a bit fuzzy about implicits in Scala. Does anybody have an idea?

Edit: Added VmdbLane.scala:

package de.x.vmdbplanningvalues

import io.circe.Decoder.Result
import io.circe._

sealed trait VmdbLane {
  override def toString: String = VmdbLane.toEnum(this)
}

object VmdbLane {

  case object New extends VmdbLane
  case object CarryOver extends VmdbLane
  case object Sale extends VmdbLane
  case object Sum extends VmdbLane

  def toEnum(e: VmdbLane): String =
    e match {
      case New => "new"
      case CarryOver => "carryOver"
      case Sale => "sale"
      case Sum => "sum"
    }

  def fromEnum(s: String): Option[VmdbLane] =
    Option(s) collect {
      case "new" => New
      case "carryOver" => CarryOver
      case "sale" => Sale
      case "sum" => Sum
    }

  implicit val jsonFormat: Encoder[VmdbLane] with Decoder[VmdbLane] =
    new Encoder[VmdbLane] with Decoder[VmdbLane] {
      override def apply(a: VmdbLane): Json = Encoder.encodeString(toEnum(a))
      override def apply(c: HCursor): Result[VmdbLane] =
        c.value.asString.flatMap(s => fromEnum(s)) match {
          case Some(a) => Right(a)
          case None => Left(DecodingFailure("VmdbLane", c.history))
        }
    }
}

CodePudding user response:

The problem was not related to Circe it is related to how the custom doobie type mapping works. If you include something like inside the VmdbLane object:

implicit val natGet: Get[VmdbLane] = Get[String].map(in => {
    in match {
      case "New"       => New
      case "CarryOver" => CarryOver
      case "Sale"      => Sale
      case "Sum"       => Sum
    }
  })

implicit val natPut: Put[VmdbLane] = Put[String].contramap {
    case New       => "New"
    case CarryOver => "CarryOver"
    case Sale      => "Sale"
    case Sum       => "Sum"
  }

The compiler should include the mapping an it should work.

  • Related