2014-01-05 5 views
0

Я пытаюсь реализовать контроллер в Play2, который предоставляет простой api для REST-стиля для моих db-таблиц. Я использую squeryl для доступа к базе данных и spray-json для преобразования объектов в/из JSONКак реализовать общий REST api для таблиц в Play2 с squeryl и spray-json

Моей идеи иметь один общий контроллер, чтобы сделать всю работу, поэтому я создал следующие маршруты в conf/routes:

GET /:tableName    controllers.Crud.getAll(tableName) 
GET /:tableName/:primaryKey controllers.Crud.getSingle(tableName, primaryKey) 

.. и следующий контроллер:

object Crud extends Controller { 
    def getAll(tableName: String) = Action {..} 
    def getSingle(tableName: String, primaryKey: Long) = Action {..} 
}   

(Да, отсутствует создание/обновление/удаление, но давайте читать работать первым)

Я сопоставляюсь таблицы к случаю классов расширенной squeryl-х Schema:

object MyDB extends Schema { 
    val accountsTable = table[Account]("accounts") 
    val customersTable = table[Customer]("customers") 
} 

И я сказал распылительному о JSON моего случая классах, так что он знает, как преобразовать их.

object MyJsonProtocol extends DefaultJsonProtocol { 
    implicit val accountFormat = jsonFormat8(Account) 
    implicit val customerFormat = jsonFormat4(Customer)  
} 

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

Это похоже на проблему с распылителем-json, которая возникает, когда я пытаюсь преобразовать список объектов в json в мою функцию getAll.

Вот моя общая попытка:

def getAll(tableName: String) = Action { 

    val json = inTransaction { 

    // lookup table based on url 
    val table = MyDB.tables.find(t => t.name == tableName).get 

    // execute select all and convert to json 
    from(table)(t => 
     select(t) 
    ).toList.toJson // causes compile error 
    } 

    // convert json to string and set correct content type 
    Ok(json.compactPrint).as(JSON) 
} 

Ошибка компиляции:

[error] /Users/code/api/app/controllers/Crud.scala:29: 
Cannot find JsonWriter or JsonFormat type class for List[_$2] 
[error]  ).toList.toJson 
[error]    ^
[error] one error found 

Я предполагаю, что проблема может быть, что JSON-библиотека должна знать, во время компиляции, которые тип модели Я бросаю на него, но я не уверен (обратите внимание на List[_$2] в этой ошибке компиляции). Я попытался следующие изменения в код, который компилировать и результат операции:

  1. Удалите общий табличный (MyDB.tables.find(.....).get) и вместо того, чтобы использовать конкретный экземпляр таблицы, например, MyDB.accountsTable. Доказывает, что сериализация JSON для работы. Однако это не является общим, для него требуется уникальный контроллер и конфигурация маршрута для таблицы в db.
  2. Конвертировать список объектов из запроса db в строку перед вызовом toJson. I.e: toList.toJson ->toList.toString.toJson. Доказывает, что общий поиск таблиц работы Но не правильный ответ JSON, так как это строка-сериализовать список объектов ..

Мысли кого-нибудь?

ответ

1

Ваша догадка правильная. MyDb.tables - это Seq [Таблица [_]], другими словами, он может содержать любой тип таблицы.Компилятор не может понять, какой тип таблицы вы найдете с помощью метода find, и похоже, что тип необходим для преобразования JSON. Есть способы обойти это, но вам нужен какой-то доступ к классу модели.