Slick - optionally including / omitting a large column
Asked Answered
O

1

1

Suppose I have a table with a number of small columns, and a large (say BLOB) column:

  case class Thing(id: Int, small1: String, small2: String, small3: String, large: String)

  class ThingMapping(tag: Tag) extends Table[Thing](tag, "things") {

    def id = column[Int]("id", O.PrimaryKey, O.NotNull, O.AutoInc)
    def small1 = column[String]("small1")
    def small2 = column[String]("small2")
    def small3 = column[String]("small3")
    def large = column[String]("large")

    def * = (id, small1, small2, small3, large) <> (Thing.tupled, Thing.unapply)

  }

Under some circumstances, I'd like to query the table for all the columns except the large column. In others, I'd like to include it. I prefer to use case classes rather than tuples.

Is there good pattern in Slick for doing this?

Options I've considered:

  1. Having two mappings -- a "skinny" and "fat" mapping.
  2. Splitting out the large column into a separate table, then joining it in if required.
Onesided answered 27/8, 2014 at 10:59 Comment(3)
Why not define large as Option[String] on the Thing case class and optional in the table definition and then add another selection def like def allNoLarge = (id, small1, small2, small3) where you don't select the large field from the db. Then you leave it up to the calling code to pick which selection def is used.Periodontics
@Periodontics -- at the moment, my calling code uses things like: val things = TableQuery[ThingMapping]. How would that fit in with having multiple selection defs in the mapping?Onesided
you can still use the TableQuery as the starting point, and then use the .map method on it to produce a new query that only selects certain columns. I'll add an answer showing this.Periodontics
P
-1

I think what you need here is the map function on your TableQuery to allow you to select only a subset of fields. So something like this:

case class Thing(id: Int, small1: String, small2: String, small3: String, large: String)
case class LiteThing(id: Int, small1: String, small2: String, small3: String)
class ThingMapping(tag: Tag) extends Table[Thing](tag, "things") {
  def id = column[Int]("id", O.PrimaryKey, O.NotNull, O.AutoInc)
  def small1 = column[String]("small1")
  def small2 = column[String]("small2")
  def small3 = column[String]("small3")
  def large = column[String]("large")
  def * = (id, small1, small2, small3, large) <> (Thing.tupled, Thing.unapply)
}
val things = TableQuery[ThingMapping]

val liteThingQuery = things.map(t => LiteThing(t.id, t.small1, t.small2, t.small3))

So I added another case class called LiteThing that represents the subset of fields, excluding the large column. I then use map to create a new query that will not select that large field and it maps to a LiteThing. I have no compiled this, but I'm pretty sure this is the direction you want to go in. I got this from the Hello Slick Activator Template, in the section "Selecting Specific Columns" (after fully expanding the tutorial info).

You can play around with alternatives like

def small = (id, small1, small2, small3)
def * = (small, large)

or

def small = (id, small1, small2, small3)
def * = small ~ large <> (Thing.tupled, Thing.unapply)

And use

things.map(_.small)
Periodontics answered 1/9, 2014 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.