Search code examples
playframeworkslick

Many-to-Many version of a slick extension method


The slick docs show how to create an Extensions implicit to get relationships between tables:

implicit class PersonExtensions[C[_]](q: Query[People, Person, C]) {
  // specify mapping of relationship to address
  def withAddress = q.join(addresses).on(_.addressId === _.id)
}

How can you create a withAddresses using a Many-to-Many table, instead of a single relationship?

Eg I'd like to be able to do similar to the following, which is a plural version of the singular example in the linked docs:

val chrisQuery: Query[People,Person,Seq] = people.filter(_.id === 2)
val addressesQuery: Query[Addresses,Address,Seq] = chrisQuery.withAddresses.map(_._2)
val addresses = db.run(addressQuery.result)

using some Mapping table eg PersonAddresses


Solution

  • You just have to define the double type from where the Extensions starts, this being the union tuple, example:

     implicit class PersonExtensions[C[_]](q: Query[(People, Addresses), (Person, Address), C]) {
        def withCities = for {
          (people, address) <- q
          city <- Cities if address.cityCode === city.code
        } yield (people, address, city)
      }
    

    Then you could ask something like:

      val addressesWithCitiesQuery = addressesQuery.withCities
      val addressesWithCities = db.run(addressesWithCitiesQuery.result)
    

    This is based on the pimp my library but set to Slick ... where the input is the value to extend, you can see more in this post: https://danielasfregola.com/2015/06/08/pimp-my-library/