Knows Not Much
Knows Not Much

Reputation: 31526

Creating a single column table with Slick

I am pretty used to writing the standard slick boiler plate code like this.

Suppose I am creating a table called Foo with columns id and name. We can write

case class Foo(id: Long, name: String)
final class FooTable(tag: Tag) extends Table[Foo](tag, "foo") {
   def id = column[Long]("id")
   def name = column[String]("name")
   def * = (id, name) <> (Foo.tupled, Foo.unapply)
}

But what if I wanted a single column table where Foo just has a name. The code below does not compile because Now Foo does not have the tupled method anymore.

case class Foo(name: String)
final class FooTable(tag: Tag) extends Table[Foo](tag, "foo") {
   def name = column[String]("name")
   def * = (name) <> (Foo.tupled, Foo.unapply)
}

I found this thread on SO

Scala projections in Slick for only one column

and changed my code to

case class Foo(name: String)
final class FooTable(tag: Tag) extends Table[Foo](tag, "foo") {
   def name = column[String]("email_address")
   def * = (name)
}

but still doesn't compile

Upvotes: 2

Views: 763

Answers (3)

Paul Dolega
Paul Dolega

Reputation: 2476

I believe previous answers already solve this particular problem. I think however there is one thing worth to add here.

There is nothing in Slick that requires you to use case classes as an unpacked type (unpacked type being kind of your model, in this case Foo).

In your projection here:

def * = (id, name) <> (Foo.tupled, Foo.unapply)

you could pass whatever two functions you want assuming that:

  • the first one will create your unpacked type out of tuple (2+ columns in your projection) or value (1 column projection)

  • second would create tuple (again in case of 2+ columns in projection) or
    value (1 column projection).

It is only convenient that case classes have such methods generated out of the box (tupled, apply, unapply).

I hope this clarifies that even if you would be lacking such methods it is always possible (at worst case) to e.g. create your functions that would fulfill given requirements.

Upvotes: 2

Knows Not Much
Knows Not Much

Reputation: 31526

Found another answer as well

case class Foo(name: String)
final class FooTable(tag: Tag) extends Table[Foo](tag, "foo") {
   def name = column[String]("name")
   def * = name <> (Foo, Foo.unapply)
}

Upvotes: 0

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

Use Foo.apply _ in case of single parameter. Your code becomes the following

case class Foo(name: String)

final class FooTable(tag: Tag) extends Table[Foo](tag, "foo") {
  def name = column[String]("name")
  def * = (name) <> ((Foo.apply _), Foo.unapply)
}

Explanation:

scala> case class Foo(name: String)
defined class Foo

scala> Foo.apply _
res0: String => Foo = <function1>

In case of single parameter case class Foo.apply _ returns a function1 which is what is required.

But in case of more than one parameter this is not possible so doing .tupled is expected.

Upvotes: 3

Related Questions