2016-04-03 22 views
1

我使用Play 2.4與Slick 3.1.x,特別是Slick-Play plugin v1.1.1。首先,某些上下文...我有在DAO以下搜索/過濾器的方法,其中連接在一起4種機型:將一系列來自平滑單點連接的結果映射到Json

def search(
       departureCity: Option[String], 
       arrivalCity: Option[String], 
       departureDate: Option[Date] 
      ) = { 
    val monadicJoin = for { 
     sf <- slickScheduledFlights.filter(a => 
       departureDate.map(d => a.date === d).getOrElse(slick.lifted.LiteralColumn(true)) 
      ) 
     fl <- slickFlights if sf.flightId === fl.id 
     al <- slickAirlines if fl.airlineId === al.id 
     da <- slickAirports.filter(a => 
       fl.departureAirportId === a.id && 
       departureCity.map(c => a.cityCode === c).getOrElse(slick.lifted.LiteralColumn(true)) 
      ) 
     aa <- slickAirports.filter(a => 
       fl.arrivalAirportId === a.id && 
       arrivalCity.map(c => a.cityCode === c).getOrElse(slick.lifted.LiteralColumn(true)) 
      ) 
    } yield (fl, sf, al, da, aa) 

    db.run(monadicJoin.result) 
    } 

從這個輸出是包含序列的載體,例如:

Vector(
    (
    Flight(Some(1),123,216,2013,3,1455,2540,3,905,500,1150), 
    ScheduledFlight(Some(1),1,2016-04-13,90,10), 
    Airline(Some(216),BA,BAW,British Airways,United Kingdom), 
    Airport(Some(2013),LHR,Heathrow,LON,...), 
    Airport(Some(2540),JFK,John F Kennedy Intl,NYC...) 
), 
    (
    etc ... 
) 
) 

我目前呈現JSON在控制器通過調用.toJson在地圖上並插入該向量(以下results PARAM),像這樣:

flightService.search(departureCity, arrivalCity, departureDate).map(results => { 
    Ok(
     Map[String, Any](
      "status" -> "OK", 
      "data" -> results 
     ).toJson 
    ).as("application/json") 
}) 

雖然這種WOR的ks,它產生output in an unusual format;每個結果對象中的結果數組(行),連接使用鍵:「_1」,「_2」等嵌套在對象內。

所以問題是:我應該如何進行重組呢?

在Slick文檔中似乎沒有具體涵蓋這類場景的任何內容。因此,我想感謝一些關於重構這個Seq向量的最佳方式的意見,以期重命名每個聯接,甚至將它們展開並只保留某些字段?

在DAO搜索方法返回之前(通過某種方式進行映射?)或者在從搜索方法中取回Future results Vector之後在控制器中執行此操作嗎?

或者我想知道是否應該使用transformer或許可以將這種突變完全抽象出來?

回答

0

你需要JSON Reads/Writes/Format Combinators

首先你必須有Writes[T]爲所有的類(FlightScheduledFlightAirlineAirport)。 簡單的方法是使用JSON宏

implicit val flightWrites: Writes[Flight] = Json.writes[Flight] 
implicit val scheduledFlightWrites: Writes[ScheduledFlight] = Json.writes[ScheduledFlight] 
implicit val airlineWrites: Writes[Airline] = Json.writes[Airline] 
implicit val airportWrites: Writes[Airport] = Json.writes[Airport] 

您必須實現OWrites[(Flight, ScheduledFlight, Airline, Airport, Airport)]的矢量項目也。例如:

val itemWrites: OWrites[(Flight, ScheduledFlight, Airline, Airport, Airport)] = (
    (__ \ "flight").write[Flight] and 
    (__ \ "scheduledFlight").write[ScheduledFlight] and 
    (__ \ "airline").write[Airline] and 
    (__ \ "airport1").write[Airport] and 
    (__ \ "airport2").write[Airport] 
).tupled 

寫整個VectorJsAray使用Writes.seq[T]

val resultWrites: Writes[Seq[(Flight, ScheduledFlight, Airline, Airport, Airport)]] = Writes.seq(itemWrites) 

我們都來響應你的數據

flightService.search(departureCity, arrivalCity, departureDate).map(results => 
    Ok(
    Json.obj(
     "status" -> "Ok", 
     "data" -> resultWrites.writes(results) 
    ) 
) 
+0

非常感謝您的詳細答覆。我已經爲所有使用Json宏的類編寫了[Writer],它只是從連接查詢返回的Vector,我不知道該如何處理。目前,DAO中的搜索方法只是返回一個包含上述對象序列的泛型Vector。我是否需要定義一個新對象作爲結果Vector的載體,其中我添加了'Writes.seq [T]'類型的resultWrites val?否則,應該去哪裏? –

+0

好吧,通過在控制器中的'flightService.search'調用上面添加你建議的內容,讓它工作。我不相信這是正確的地方,但我猜'val itemWrites:OWrites ...'和'val resultWrites:Writes ...'可以通過特質混合。在控制器中使用它不太合適,但同樣定義一個僞模型對象來保存結果序列也沒有什麼意義。無論如何,再次感謝您的指導,這是一個很大的幫助。 –

+0

你可以定義你的僞模型,但是你必須實現自己的Writes。 'Writes.tupled'只是''Tuple'實現的這種僞模型的作者。你的寫作很簡單,更復雜我試着移動控制器以外的動作僅用於測試。您可以將這個寫入伴隨對象(如果控制器作爲類實現)來進行一次初始化。 –