Тот, кому доводилось иметь дело с выбором ORM для Scala, наверняка, наслышан о таких библиотеках, как Slick (Scala Query), Squeryl, Circumflex и пр., и, не менее вероятно, согласится со следующими утверждениями: они не абстрагируются от реляционных концепций, они требуют описания модели специфическими способами, API зачастую запутан и рассредоточен, и, наконец, то, насколько предложенные этими библиотеками абстракции в действительности упрощают работу с базой данных является, по меньшей мере, сомнительным.
Так и родилась идея создать фреймворк, который
- возведёт абстракцию над базой данных до более высокого уровня, представляя её через стандартные типы данных Scala: примитивы, кортежи, опции, коллекции и тд., а так же стандартные кейс-классы, представляющие собой сущности
- выполняя первую задачу, будет «чистым», что означает полное исключение концепций реляционной стороны из API фреймворка: никаких таблиц, строк и реляционных связей,
- возведёт в принцип основы функционального программирования: только немутируемые типы данных, сведение State к минимуму,
- будет выполнять за пользователя всё, что он может, за счёт чего достигнет минимизации boilerplate.
Как видите, задачи все стояли достаточно бескомпромиссные, однако они были решены. За счёт этого удалось добиться последовательности, простоты и вытекающей интуитивности фреймворка, — и это при отнюдь не слабых возможностях. Boilerplate удалось, и вовсе, исключить. Дальше код.
// Модель данных.
// Никаких аннотаций, никаких особых типов данных и пр. Самые обыкновенные
// кейс-классы, которые Вы можете использовать в любом месте приложения -
// к примеру, передавать во view.
case class Artist ( name : String, genres : Set[Genre] )
case class Genre ( name : String )
// Объявление базы данных. Все настройки SORM указываются тут же:
import sorm._
object Db extends Instance (
entities = Set() + Entity[Artist]() + Entity[Genre](),
url = "jdbc:h2:mem:test"
)
// Сохраним несколько значений в БД:
val metal = Db.save( Genre("Metal") )
val rock = Db.save( Genre("Rock") )
Db.save( Artist("Metallica", Set() + metal + rock) )
Db.save( Artist("Dire Straits", Set() + rock) )
// Получим кое-что:
// Option[Artist]:
val metallica = Db.query[Artist].whereEqual("name", "Metallica").fetchOne()
// Stream[Artist]:
val rockArtists = Db.query[Artist].whereEqual("genres.name", "Rock").fetch()
Как говорится, that's all folks! Это полный код программы, создающей базу данных и сохраняющей и запрашивающей из неё сущности. Никаких дополнительных действий со стороны пользователя для её работоспособности не требуется.
Информацию по установке, документацию, туториал и сравнение со Slick (Scala Query) Вы найдёте на официальном сайте SORM.
Спойлер: в следующих версиях SORM грядут макросы и вытекающее ещё большее упрощение API.
Автор: mojojojo