Как абстрагировать определение столбца между скользкими таблицами? - PullRequest
2 голосов
/ 09 июля 2019

Я пытаюсь добавить новый столбец в несколько таблиц в существующем скользком приложении. Столбец одинаков во всех таблицах: добавление идентификатора клиента в таблицу для включения фильтрации по клиенту во всех наших запросах. Однако в некоторых случаях этот идентификатор будет необязательным: поэтому мне нужно обрабатывать оба случая, используя наши существующие запросы.

Проблема возникает, когда я пытаюсь написать некоторый код, чтобы использовать новый столбец для фильтрации на новом клиенте. Я хочу написать метод, чтобы обернуть запросы к таблицам для всех измененных таблиц и, при желании, отфильтровать их на клиенте, но при попытке написать метод, выполняющий эту задачу, происходит сбой slick.

Я попытался добавить абстрактный класс, расширяющий Table в пятно, чтобы обернуть таблицы, где я хочу добавить новый клиентский столбец, как таковой

  abstract class ClientTable[T](tag: Tag, name: String) extends Table[T](tag,name)  {
    def client: Rep[Option[Int]]
  }

  class Feeds(tag: Tag) extends ClientTable[Feed](tag, "feeds") {
    def id: Rep[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)

    def name: Rep[String] = column[String]("name")

    ...

    def client: Rep[Option[Int]] = column[Option[Int]]("client")

    private val list = id :: name :: ... :: client :: HNil

    def * : ProvenShape[Feed] = list.mappedWith(Generic[Feed])
  }

Однако, похоже, что это вообще не работает со сликом.

В целом, я надеюсь заставить этот метод (или что-то подобное) работать:

  def tableView[T <: ClientTable[E], E] (tableQuery: TableQuery[E], clientId: Option[Int]) = {
    clientId match {
      case Some(id) => tableQuery.filter(_.client === id)
      case None => tableQuery
    }
  }
}

, чтобы я мог заменить определение TableQuery в запросах на private val xTable = tableView(TableQuery[X], clientId), а затем, надеюсь, не нужно менять все мои существующие запросы.

1 Ответ

1 голос
/ 11 июля 2019

Нет ничего хуже, чем оставшийся без ответа вопрос о переполнении стека! Таким образом, вот как я решил эту проблему.


Метод, над которым я работал, оказался верным, я просто немного ошибся в своих генериках. Рабочая версия выглядит так:

def tableView[T <: ClientTable[E], E <: ClientColumn](tableQuery: TableQuery[T], clientId: Option[Int]): Query[T, T#TableElementType, Seq] = {
    clientId match {
      case Some(id) => tableQuery.filter(_.client === id)
      case None => tableQuery
    }
  }

В определениях таблиц вам необходимо расширить тип Table с помощью реализации, в которой есть столбец client:

abstract class ClientTable[T](tag: Tag, name: String) extends Table[T](tag, name) {
  def client: Rep[Option[Int]] = column[Option[Int]]("client")
}

и расширяйте ваши классы падежей строк признаком, который добавляет поле client ко всем из них как таковое

trait ClientColumn {
  def client: Option[Int]
}

case class Feed(id: Int = 0,
                name: String,
...
                client: Option[Int]) extends ClientColumn

Теперь метод tableView будет работать должным образом, хотя, по-видимому, только при передаче параметров типа, например, val x = tableView[X, x](TableQuery[X], client), поскольку, похоже, Scala не может определить типы обоих общих параметров.

Одна вещь, о которой стоит упомянуть, это то, что я не использую Slick для создания своей таблицы или операторов ddl, вместо этого я использую flyway. Использование этого метода с abstract class и trait может не работать в этом случае.

В любом случае, удачи всем, кто найдет этот вопрос и ответ в будущем!

...