2016-11-04 3 views
0

Я хотел бы предоставить метод выбора контроллеру, который принимает имя таблицы как параметр и возвращает результат запроса SELECT как JSON. До сих пор я сделал это:Scala Slick: как сериализовать результат запроса в таблице переменных

def specialSelect(tableName: String) = Action.async { 
    val tq: TableQuery[_] = tableObjectFactory(tableName) 
    val res: Future[Seq[_]] = db.run(tq.result) 
    res.map { p:Seq[_] => Ok(p.toJson) } 
} 

где tableObjectFactory берет свое имя таблицы и возвращает TableQuery конкретного типа:

def tableObjectFactory(tableName: String): TableQuery[_] = { 
    tableName match { 
    case "users" => TableQuery[Users] 
    case "projects" => TableQuery[Projects] 
    } 
} 

Если не удается, потому что нет JSON сериализатор определяется аа общей Seq[_] (фактически _ должен быть Product with Serializable, не уверен, что это помогает).

Имя таблицы неизвестно заранее (найдено в URL-адресе, например, в "/special_select/<tableName>"), и у меня есть 120 таких таблиц, поэтому я не могу просто реализовать его для каждой таблицы.

Есть ли способ сериализации любойSeq[_], зная, что _ всегда является результатом Slick строки (например, случай класса UsersRow), независимо от таблицы?

Я читал об общих DAO и ActiveSlick, но я не уверен, что должен зайти так далеко.

+0

Каждый класс класса будет иметь различное количество и тип полей, поэтому было бы сложно написать генерал Джсон. Попробуйте предоставить 'implicit json format' для каждой модели. 'Json.format [Пользователь]' внутри объекта-компаньона. – pamu

+0

Scala не волнует, какой форматировщик Json я предоставляю для каждого из объектов строки, потому что он видит только 'Seq [(Product with Serializable)]' или что-то подобное. Он не может знать, что классы case, которые я предоставил для форматирования Json, являются единственными, которые он когда-либо видел. – JulienD

+1

верно, но количество кортежей в Продукте зависит от объекта, который вы передаете. Таким образом, не может быть одного формата, который может объяснить, как преобразовать продукт в JSON. Вы должны использовать это решение, используя Reflection. попробуйте использовать библиотеку Gson – pamu

ответ

0

Gson работал, спасибо @pamu. Добавить

libraryDependencies += "com.google.code.gson" % "gson" % "2.8.0" 

к build.sbt, то это будет конвертировать любые Seq[_] или строки в JsArray, которые могут быть предоставлены в качестве отклика HTTP:

import com.google.gson.Gson 
import play.api.libs.json._ 

val gson: Gson = new Gson() 

def slickToJson(res: Seq[_]): JsArray = { 
    JsArray(res.map(gson.toJson).map(Json.parse)) 
} 

// in controller Action.async: 
db.run(...).map(p => Ok(slickToJson(p))) 

Ряды упорядочиваются в строку с помощью Gson, а затем разобран назад в JsObjects от Play api, затем добавьте JsArray. Я не мог найти лучшего.