Book Image

Play Framework Cookbook - Second Edition

By : Alexander Reelsen, Giancarlo Inductivo
Book Image

Play Framework Cookbook - Second Edition

By: Alexander Reelsen, Giancarlo Inductivo

Overview of this book

<p>As web and mobile systems become more sophisticated, anchoring systems in a mature, solid framework has become increasingly important. Play 2 provides developers with the necessary tools to build robust web applications.</p> <p>This book is a compilation of useful recipes aimed at helping developers discover the power of Play 2. The introductory section serves as a primer to Play Framework, wherein all the fundamentals of the framework are covered extensively. It then explains the usage of controllers and how modules can be leveraged for optimal performance. Next, the book walks you through creating and using APIs, followed by extensive real-world applications. Finally, you will learn to manage applications post production.</p>
Table of Contents (15 chapters)
Play Framework Cookbook Second Edition
Credits
About the Authors
About the Reviewers
www.PacktPub.com
Preface
Index

Using Anorm (Scala) and database evolutions with MySQL


Play Framework 2.x includes Anorm, a useful data access library for Scala-based Play applications. To be able to use Anorm, ensure that Anorm and a suitable MySQL driver are declared as project dependencies in foo_scala/build.sbt.

For this recipe, we will be utilizing Anorm with database evolutions. Play Framework 2.x gives developers a way to manage database migrations. Database migrations are useful for tracking schema changes during the course of application development. Database evolutions are enabled by default but can be disabled in conf/application.conf using the following settings:

evolutionplugin=disabled

Evolution scripts are stored in the conf/evolutions/default/ directory. For more information regarding database evolutions, please refer to Play's online documentation at https://www.playframework.com/documentation/2.3.x/Evolutions.

You need to perform the following steps to utilize Anorm:

  1. Add the Anorm dependency to build.sbt:

        libraryDependencies ++= Seq(
          jdbc,
          anorm,
       "mysql" % "mysql-connector-java" % "5.1.28"
        )
  2. Ensure that Anorm and MySQL are configured properly in conf/application.conf:

        db.default.driver= com.mysql.jdbc.Driver
        db.default.url="jdbc:mysql://localhost/YOUR_DB"
        db.default.user=YOUR_USER
        db.default.password=YOUR_PASSWORD
  3. For the next recipes, we need to create our products table in our MySQL database. Create our first database evolution file 1.sql in conf/evolutions/default and add the following SQL statements:

        # --- !Ups
        CREATE TABLE Products (
          id INT NOT NULL AUTO_INCREMENT,
          name VARCHAR(100) NOT NULL,
          PRIMARY KEY (id)
        );
    
    # --- !Downs
        DROP TABLE Products;

There's more…

The following sections display various database-oriented operations using Anorm.

Creating a new record

The following code snippet will create a new record:

   DB.withConnection { implicit c =>
     SQL("INSERT INTO Products(id, name) VALUES ({id}, {name});")
        .on('id -> product.id, 'name -> product.name).executeInsert()
   }

Updating a record

The following code snippet will update a record:

    
   DB.withConnection { implicit c =>
      SQL("UPDATE Products SET name = {name} WHERE id = {id}")
       .on('name -> product.name, 'id -> product.id).executeUpdate()
   }

Deleting a record

The following code snippet will delete a record:

    
   DB.withConnection { implicit c =>
      SQL("DELETE FROM Products WHERE id={id};")
       .on('id -> id).executeUpdate()
   }Querying a record

The following code snippet will query a record:

    DB.withConnection { implicit c =>
      SQL("SELECT * FROM Products WHERE id={id};")
       .on('id -> id).executeQuery().singleOpt(defaultParser)
    }

The following code snippet will retrieve a record:

    DB.withConnection { implicit c =>
     SQL("SELECT * FROM Products;").executeQuery().list(defaultParser)
   }

Finally, we can combine all of these functions in a companion object called Product:

    package models

    import play.api.db.DB
    import play.api.Play.current
    import anorm._
    import anorm.SqlParser.{str, int}

    case class Product(id: Long, name: String)

    object Product {
      val defaultParser = int("id") ~ str("name") map {
          case id ~ name  => Product(id, name)
         }

      def save(product: Product) = {
        DB.withConnection { implicit c =>
      SQL("INSERT INTO Products(id, name) VALUES ({id}, {name});")
                  .on('id -> product.id, 'name -> product.name).executeInsert()
        }
          }
      

      def update(product: Product) = {
        DB.withConnection { implicit c =>
               SQL("UPDATE Products SET name = {name} WHERE id = {id}")
                .on('name -> product.name, 'id -> product.id).executeUpdate()
            }
          }

      
      def delete(id: Long) = {
        DB.withConnection { implicit c =>
               SQL("DELETE FROM Products WHERE id={id};")
           .on('id -> id).executeUpdate()
        }
          }

      
      def get(id: Long) = {
        DB.withConnection { implicit c =>
      SQL("SELECT * FROM Products WHERE id={id};")
        .on('id -> id).executeQuery().singleOpt(defaultParser)
        }
          }
      
      def all = {
        DB.withConnection { implicit c =>
      SQL("SELECT * FROM Products;").executeQuery().list(defaultParser)
        }
          }
    }