Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compile a parametrized update in Slick 3.1?

Although the docs say you can compile updates, I'm having trouble getting Slick 3.1 to compile an update where the value to be updated is passed into the compiled block.

For my use case, I want to find a row with a given key where the deactivation is null and set the deactivation time to a new timestamp.

The obvious thing I'd want to do is this:

  private[this] lazy val updateDeactiveTime = Compiled { (settingName: Rep[String], time: Rep[Instant]) =>
    settings
      .filter { row => row.name === settingName && row.deactivatedAt.isEmpty }
      .map { _.deactivatedAt }
      .update(Some(time))
  }

Unfortunately, this gives me a complaint that update can't take a Rep[Option[Instant]]: it wants an Option[Instant].

I understand that Slick (unfortunately) doesn't allow you to use a dynamically calculated value in an update. Per the docs, the workaround for things like limit operations is to use a ConstColumn[…]. Dutifully, I tried passing in a ConstColumn[Option[Instant]], hoping there'd be some implicit conversion or extension, but I still get the complaint that it must be a literal Option[Instant].

Of course I have the literal instant, but there's not much point compiling the update if I have to recompile it every time the target value changes.

If I were to use a LiteralColumn[…], I could call _.value, but Compiled won't let me require a LiteralColumn. Compiled also won't allow me have my parameter be time: Instant.

like image 255
Sarah G Avatar asked Jul 08 '16 07:07

Sarah G


1 Answers

You do the update operation outside of the part that's compiled. This still provides the benefits of compilation.

  private[this] lazy val deactiveTime = Compiled { (settingName: Rep[String]) =>
    settings
      .filter { row => row.name === settingName && row.deactivatedAt.isEmpty }
      .map { _.deactivatedAt }
  }
  def updateDeactiveTime(settingName: String, time: Instant) = {
    deactiveTime(settingName).update(Some(time))
  }

It turns out that when you do Compiled, Slick actually creates four different compilation targets that it will use for insert, update, delete and select. Each specific form is fully compiled on first use. You can see this explicitly in the API for CompiledFunction.

like image 107
Sarah G Avatar answered Sep 23 '22 10:09

Sarah G