Search code examples
postgresqlscalafunctional-programmingslick

Passing TableQuery object as a parameter results in strange type error in Slick/Scala but not when injected


I am writing a function to persist some data to a Slick postgres database. Here is my table persisting ClientRow objects:

class ClientTable(tag: Tag) extends Table[ClientRow](tag, "clients") {
  def clientId = column[Long]("client_id", O.PrimaryKey, O.AutoInc)
  ...
  override def * =
        (clientId, phoneNumber, firstName, lastName, trainerId, dateRegistered) <> (ClientRow.tupled, ClientRow.unapply _)
}

I tried writing the following function to inject the table and database dependencies through composition:

type PersistClient[A <: AbstractTable[_]] =
    DatabaseDef => TableQuery[A] => ClientInfo => Future[ClientId]

val persist: PersistClient[ClientTable] = db =>
      clients =>
        info => {
          val action = clients.returning(
            clients.map(_.clientId) += toRow(info)
          )
          db.run(action).map(constructId(_))
    }

Here ClientInfo and ClientId are just case classes with data. toRow has signature ClientInfo => ClientRow, it converts the strongly typed/highly structured data in the Info object to more primitive data for SQL. constructId creates a string ID out of the Long for logging readability (I like id.client.<number>)

Under toRow I get the following error:

type mismatch;
 found   : messager.Client.persistence.ClientRow
 required: Long

Strangely, if I write the same function while injecting the dependencies into the class that houses this function as so:

val persistClient: ClientInfo => Future[ClientId] = info => {
      val action = clients.returning(clients.map(_.clientId)) += toRow(info)
      db.run(action).map(constructId(_))
    }

Here clients and db are the same types as before, but are just injected into the class as dependencies rather than inputs to a function. What gives? Why can't my nice curried code compile?


Solution

  • It looks like the argument to clients.returning is a insert that returns the number of rows changed. That doesn't look right, and is different from the version you have that works.