Introducción: Play Framework 2 (Parte II: El Modelo)

El otro día hablábamos sobre Play Framework 2 y hacíamos una muy breve introducción al lenguaje de programación Scala. Hoy vamos a introducirnos un poco más en las entrañas del framework para descubrir un poco su uso.

Vamos a utilizar Anorm para lidiar con la base de datos (en Play para Scala no hay ORMs) y nuestra intención es crear una página web sencilla y sin pretensiones así pues, vamos al lío.

Crear una aplicación


Para crear un nuevo proyecto con Play 2 tan solo tenemos que instalarlo siguiendo la guía de instalación y ejecutar el comando play new <nombre> en el directorio donde queremos crearlo.

La utilidad de línea de comandos play es un sbt modificado para facilitar su uso con el framework. Para quien no conozca el proyecto SBT le recomiendo que se lea la documentación del mismo pues es una especie de Maven para Scala y viene muy bien.

Configurar la base de datos


Para configurar que tipo de base de datos vamos a usar en nuestras aplicaciones desarrolladas con Play 2 debemos editar el archivo “conf/application.conf”, en nuestro caso vamos a crear una base de datos tipo h2 residente en memoria:
db.default.driver=org.h2.Driver
db.default.url=“jdbc:h2:mem:play”

El Modelo de Datos


Como ya hemos dicho, Play con Scala no provee de un ORM por defecto, tampoco he mirado si existe algún plug-in para dotar a nuestras aplicaciones de un ORM para Scala, es posible que exista algo, pero a mi la librería de abstracción de bases de datos Anorm (Anorm is Not an Object Relational Mapper) me es más que suficiente.

Anorm requiere que definamos un script para la creación del esquema de la base de datos y otro script para eliminarlo ya que no soporta la generación / eliminación automática del esquema. Play 2 buscará dicho script en el directorio “conf/evolutions/default/“ todos aquellos archivos con extensión .sql y numerados en orden.

Por lo tanto, si en el directorio tenemos dos archivos denominados 1.sql y 2.sql Anorm primero ejecutará 1.sql y después ejecutará 2.sql como una evolución del esquema, esto puede tener aplicaciones muy útiles.

Para nuestra introducción vamos a crear un modelo sencillo sin mucha historia:

# —- First database scema
# —- !Ups
create table person { id serial primary_key, firstname varchar(128) not null, lastname varchar(255) not null, age int not null
}
# —- !Downs
drop table if exists person;

Anorm hace uso de case clases como Value Objects y un objeto singleton como la interfaz de persistencia y CRUD.

Play 2 busca los archivos del modelo en el directorio “app/models/” de nuestro proyecto así que vamos a crear en ese mismo directorio un archivo denominado Person.scala donde definiremos la entidad Person:

package models
import play.api.db._
import play.api.Play.current
import anorm._
import anorm.SqlParser._
case class Person( id: Pk[Long], firstname: String, lastname: String, age: Int
)
object Person { // — Parsers
/** * Parse a Person from a ResultSet */ val simple = { get[Pk[Long]](“person.id”) ~ get[String](“person.firstname”) ~ get[String](“person.lastname”) ~ get[Int](“person.age”) map { case id~firstname~lastname~age => Person( id, firstname, lastname, age ) } }

}

Ya tenemos nuestro Value Object y nuestro singleton (cuya propiedad simple actúa como parser y mapea los valores de la base de datos a las propiedades de la case class) definido aunque al no existir ningún método aún no es demasiado útil. Si no entiendes la sintaxis de Scala te recomiendo que leas la documentación del lenguaje o bien alguna guía rápida de referencia, al menos de como se crean literales de funciones.

Si, has leido bien, literales de funciones, en Scala (así como en cualquier otro lenguaje que soporte la programación funcional) las funciones son ciudadanos de primer nivel y pueden ser utilizados como cualquier otro ciudadano de primer nivel incluida la creación mediante literales.

Ahora que tenemos nuestra entidad, vamos a añadirle algo de funcionalidad a la misma:

    /**
     * List every person
     */
    def list(): Seq[Person] = {
        DB.withConnection { implicit connection =>
            SQL(“select * from person”).as(Person.simple *)
        }
    }
/** * Find a person by id */ def findById(id: Long): Option[Person] = { DB.withConnection { implicit connection => SQL(“select * from person where id={id}”).on( ‘id -> id).as(Person.simple.singleOpt ) } }
/** * Get people that name match this pattern only */ def findByName(pattern: String): Seq[Person] = { DB.withConnection { implicit connection => SQL(“select * from person where firstname like ‘%{pattern}%’”).on( ‘pattern -> pattern).as(Person.simple.singleOpt ) } }
/** * Create a new person and save it into the database */ def create(person: Person) = { DB.withConnection { implicit connection => SQL(“insert into person values ({firstname}, {lastname}, {age})”).on( ‘firstname -> person.firstname, ‘lastname -> person.lastname, ‘age -> person.age ).executeUpdate() } }

El código anterior es autoexplicativo. Como podéis comprobar, crear una entidad con Play 2 para Scala no tiene misterio alguno (salvando la arcana sintaxis de Scala para los profanos) y su uso es muy fácil. En el próximo artículo escribiremos test unitarios para comprobar que nuestro modelo de datos se comporta como se espera de él antes de seguir con los controladores y la vista.

Hasta entonces, Happy Hacking!.

Más en Genbeta Dev | Introducción a Play Framework

Portada de Genbeta