Как конвертировать результат Slick в нужный формат? - PullRequest
1 голос
/ 30 апреля 2019

У меня есть доменный объект типа Person, который определяется в классе case следующим образом:

case class Person(personName: String, personAge: Int, personId: Long = 0)

и соответствующая таблица запросов выглядит следующим образом:

final case class PersonTable(tag: Tag) extends Table[Person](tag, "people") {

  def personId = column[Long]("person_id", O.AutoInc, O.PrimaryKey)

  def personName = column[String]("person_name")

  def age = column[Int]("person_age")

  def * = (personName, age, personId).mapTo[Person]
}

и у меня есть объект домена типа Address, который определен в случае класса следующим образом:

case class Address(houseNumber: Int, street: String
, state: String, ownerId: Long, id: Long = 0)

Соответствующий класс таблицы определен, как показано ниже. Лицо и адрес имеют отношение один ко многим ( один человек может иметь много адресов, но один адрес принадлежит только одному человеку )

final case class AddressTable(tag: Tag) extends Table[Address](tag, "addresses") {
  def houseNumber = column[Int]("house_number")

  def street = column[String]("street_name")

  def state = column[String]("state_name")

  def addressId = column[Long]("address_id", O.PrimaryKey, O.AutoInc)

  def ownerId = column[Long]("owner_id")

  def owner = foreignKey("owner_fk", ownerId, TableQuery[PersonTable])(_.personId, onDelete = ForeignKeyAction.Cascade)

  def * = (houseNumber, street, state, ownerId, addressId).mapTo[Address]
}

Я хочу вернуть следующий тип JSON-результата из моего REST API на основе Akka-http (адреса должны быть возвращены в виде массива ):

{
    "name": "shekhar",
    "age": 30,
    "id": 1234,
    "addresses": [{
            "house_number": 1,
            "street": "water street",
            "state": "foo bar",
            "owner_id": 1234,
            "address_id": 9874
        },
        {
            "house_number": 99,
            "street": "foo bar street",
            "state": "foo disk state",
            "owner_id": 1234,
            "address_id": 007
        }
    ]
}

Чтобы получить этот результат, я написал запрос, используя Slick, как показано ниже:

  val peopleQueries = TableQuery[PersonTable]
  val addressQueries = TableQuery[AddressTable]
  val query = peopleQueries.filter(_.personName === "Shekhar") joinLeft addressQueries on (_.personId === _.ownerId)
  val futureResultData = db.run(query.result)

Я получаю результат для этого в следующей структуре ( данные о человеке повторяются для каждого адреса ):

Vector(
  (Person("shekhar",30,1234),
    Some(Address(1,"Water Street","foo bar",1234,9874))
  )
  , (Person("shekhar",30,1234),
    Some(Address(99,"foo bar street","foo disk state",1234,007))
  )
)

Чтобы преобразовать вышеприведенное в ожидаемый формат JSON, я могу подождать, пока запрос БД не будет выполнен, и написать некоторый код Scala, чтобы привести его в желаемый формат, но это заблокирует запрос до завершения этой постобработки (пожалуйста, исправьте меня, если я неправильно об этом).

мой код будет выглядеть так:

futureResultData.onComplete {
  case Success(data) => // code to bring data in desired format
}

Хотелось бы узнать, есть ли способ получить результат асинхронным / неблокирующим способом ?


Благодаря Педро мне удалось найти решение этой проблемы.

Решение, которое сработало для меня, выглядит следующим образом:

futureResultData.map( x => {
        x.groupBy(_._1).mapValues(_.map(_._2.get))
})

1 Ответ

2 голосов
/ 30 апреля 2019
futureResultData.map {
  _.transformInDesiredFormat // code to bring data in desired format
}

Если вы разместите реальный код, который преобразует, я могу помочь вам больше

Фьючерсы - это монады, поэтому, когда вы наносите на карту, вы работаете с тем, что находится в будущем. Если у вас есть Future [Int] и вы отображаете это будущее, внутри карты вы работаете с Int.

Пример:

val aFuture = Future.successful(1)
aFuture.map(f=>  f+ 1)
...