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


#21

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.


#23

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)

#24

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


#25

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.


#26

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.


#27

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