У меня есть доменный объект типа 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))
})