Using Slick 3.2.0 provides classic example of why 'implicit' drives people out of Scala

expressiveness… you hit an interesting topic. Let’s talk about that.
This is one required line of code for slick to deal with autoincrement keys:

def autoInc = id.? ~ first ~ last <> (User, User.unapply _) returning id

If that is what you called “expressive” we are on opposite sides of the fence.
That code is not part of a library, it is part of an ABOMINATION of a library.

Only perl libraries can compete with the line above when it comes to lack of expressiveness. When I accidentally open a binary file with a text editor, I find text that looks like the example above.

I don’t know where that code is from but it’s wrong. It look like a combination of an older version of slick and some other things.

You just have your schema defined something like this:

case class User(id: Option[Long], first: String, last: String)
class Users(tag: Tag) extends Table[User]("users", tag) {
  val id = column[Long]("id", O.PrimaryKey)
  val first = column[String]("first")
  val last = column[String]("last")
  def * = (id.?, first, last).mapTo[User]
}
val Users = TableQuery[Users]
val forInsert = Users returning Users.map(_.id) into ((user,id) => user.copy(id=Some(id)))

def insertUser(user: User) = db.run(forInsert += user)

Usually I abstract this out (using my library slick-additions) but you can do it easily and more simply like this:

case class Entity[A](id: Option[Long], value: A)
abstract class EntityTable[A](tag: Tag, tableName: String) extends Table[Entity[A]](tableName, tag) {
  val id = column[Long]("id", O.PrimaryKey)
  def valueMapping: MappedProjection[A, _]
  def * = (id.?, valueMapping).mapTo[Entity[A]]
}
class EntityTableQuery[A, T <: EntityTable[A]](ctor: Tag => T) extends TableQuery[T](ctor) {
  val forInsert = this returning this.map(_.id) into ((ent,id) => ent.copy(id=Some(id)))

  def insertValue(value: A) = db.run(forInsert += Entity(None, value))
}


case class User(first: String, last: String)
class Users(tag: Tag) extends EntityTable[User]("users", tag) {
  val first = column[String]("first")
  val last = column[String]("last")
  def valueMapping = (first, last).mapTo[User]
}
object Users extends EntityTableQuery[User, Users](new Users(_))

Users.insertValue(User("John", "Smith"))

Note: this code has not been tried

After spending some time and some projects with slick, I totally agreed with @bentito @jdelafon opinion - ‘
Agreed. Get out of Slick whenever you can, as often as you can, for as long you can. Ignore that whacky teammate who just wants to bad mouth it yet keep fixing it to show how smart he/she is.’ I know this is a kind of hurting slick guys. But I do hope an official product should be intuitive and easy to use from its users or developers’s point of view, instead of playing wired and smart things.

I am a happy Slick user. It definitely is one of the more complex libraries for Scala. You have to deal with importing the context it needs to work, and when you hit problems it can be tough to figure out how to fix them.

But the advantages are real:

  • I’m not aware of any other option on the JVM that does SQL with the level of type safety that Slick provides (without ORM downsides).
  • It does a very good job of providing an async and reactive-friendly API on top of blocking JDBC.

In my case, these were well worth the time sunk into dealing with its complexity. Of course it is normal for others to view these trade-offs differently.

1 Like

As somebody mentioned, there are multiple alternatives in this space (I’m a happy Quill user).

After suffering some slick buyers remorse, I tried http://squeryl.org and love how you can write typesafe sql with brilliant optional handling. Website needs some updating but it has some loyal production users. Just throwing it out there.

To make Slick easier to handle (a lot easier), I use an IDE (IntelliJ) and text editors to write and view code, but I only use sbt to run projects with Slick in them. It’s pretty easy to set up and is a faster compile cycle. I make sure I keep up to date on Scala, Slick and sbt without breaking my other third parties. And before I truly understood the reach implicits could have, I definitely was held back and often bitten (#LostWeekends).

I look for up-to-date idioms set out in the documentation. Scala and Slick are evolving quickly still and that causes pain - no doubt about that. Now that sbt is 1.0.x and the collections library is more sane, Slick is a bit easier to corral. I also don’t let my Slick code out past my tables page and my DAO’s. Never. You’ll get beaten down.

Once I figured that out, Slick has been fast and easy to code. I have even used it for massively complex searches in a chained way based on it being monadic. Easy to understand and super fast. Just be pedantic and verbose and Englishy when writing.

I have the same view, Slick is complex, insanely complex, but, i can manage to create useful things on top of Slick, i think Slick is not an “end programmer” library, but something on the middle to create your data layer safely, Slick allows you to dive deep into its sea of complexity and change things that is not possible into others “end programmer” libraries, Slick way to treat everything as an typed expression is the best thing i ever worked with(I’ve worked with Quill, Elixir’s Ecto, Entity Framework, the “thing” that comes with Laravel, Doctrine and Alchemy), the way to develop custom AND ALSO typed expressions makes your development really failsafe, the worst thing i’ve hit with others libraries is the way things are done where things looks like hardcoded and hard to get around without workarounds.

Now, the thing i hate on Slick(and the mostly Scala frameworks, mainly data mappers) is the way it impacts on compile time, i have a table mapper which takes like 5min to compile because of macros and implicits of Slick, besides, you can get around it easily breaking your application in subprojects that compiles separately, also dependency injection way to develop things and repository pattern helps a lot.