Friday, December 28, 2012

Synchronous API tutorial - basics

In this tutorial we will have a look at Sprouch's synchronous API. I will show you how to add Sprouch to your project and use it to create, read, update and delete documents in CouchDB (or BigCouch or Cloudant). The source code is available at github.com/KimStebel/sprouch-tutorial in the 2.10 branch.

Let's create a new sbt project.


name := "sprouch-tutorial"

scalaVersion := "2.10.0-RC5"

Sprouch is available from its own repository on github, so we need to add that to our resolvers.


resolvers += "sprouch repo" at
             "http://kimstebel.github.com/sprouch/repository"

Now sbt will be able to resolve our dependency on sprouch.


libraryDependencies += "sprouch" % "sprouch_2.10" % "0.5.6"

Now to the actual code. First we need a few imports: sprouch.synchronous contains the main classes Couch and Database. sprouch.synchronous.dsl contains implicit conversions that allow us to use a shorter, more convenient syntax. Finally, sprouch.JsonProtocol contains methods to convert Scala types from and to JSON.


object Tutorial extends App {
 import sprouch.synchronous._
  import sprouch.synchronous.dsl._
  import sprouch.JsonProtocol._

Suppose we have a Scala class used to represent products in an online store.


  case class ShopItem(
      name: String,
      price: BigDecimal,
      description:Option[String])

We would like to store it in CouchDB. Since CouchDB stores its data as JSON documents, we first need a way to convert products to and from JSON. Since we defined ShopItem as a case class, there is an easy way to do this. We call jsonFormat3(Product) to get a JsonFormat[Product]. JsonFormat is a just trait with a read and a write method, so it is easy to implement one yourself if needed.


  implicit val productFormat = jsonFormat3(ShopItem)

Now we need to connect to CouchDB. First we create a Config object. The config object takes an ActorSystem and any configuration settings needed to connect to CouchDB. In this tutorial, we create our own actor system. In a real application you will probably already have one configured. If you don't specify any other parameters, sprouch asseumes CouchDB is running on localhost port 5894, does not require a username or password and uses plain HTTP rather than HTTPS.


  import akka.actor.ActorSystem
  val actorSystem = ActorSystem("myActorSystem")
  import actorSystem.dispatcher
  import sprouch.Config
  val config = Config(actorSystem)

Here is a different configuration that would work with cloudant.


  val config2 = Config(
      actorSystem,
      hostName="someone.cloudant.com",
      port=443,
      userPass=Some("someone" -> "password"),
      https=true
  )

Then we create a new couch object with this config. Here we can also specify a timeout for connections to the database server.


  val couch = Couch(config)

Now comes the interesting part. We get a reference to the items database or create it, if it does not already exist.


  implicit val db = try {
   couch.getDb("items") //throws an exception if the database does not exist
  } catch { case _:sprouch.SprouchException =>
    couch.createDb("items")
  }

We create a new product to put into our database


  val phone = ShopItem("Samsung S5", 500, Some("Shiny new smartphone"))

...and add the phone to the database.


  val phoneDoc = phone.create

createDoc gives us a RevedDocument[Product]. The RevedDocument contains an ID created by CouchDB (you can also pass your own ID to createDoc), the document revision returned by CouchDB and of course the phone object. Let's say we want to reduce the phone's price. We create a new Document by calling the := method and pass a new ShopItem. Since we're dealing with a case class, we can use its copy method to update the price and the description.


  val updatedPhoneDoc = phoneDoc := phone.copy(
      price = 400,
      description = Some("Shiny new smartphone. Now 20% off!")
  )

If we don't want to sell this phone anymore, we can delete it from the database. Note that we need to have the latest version of the document, because deletion will fail if the revision is not current.


  updatedPhoneDoc.delete

We output the first and second version of the phone document.


  println("First version: " + phoneDoc)
  println("Second version: " + updatedPhoneDoc)

The output is

First version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 1-3ef3ac1b402f0948d2a94a383708dcda,
    data: ShopItem(Samsung S5,500,Some(Shiny new smartphone)))
Second version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 2-9e8f214f19641582c22b09bf6fab8141,
    data: ShopItem(Samsung S5,400,Some(Shiny new smartphone.
                                       Now 20% off!)))
       

Finally we shut down the actor system.


  actorSystem.shutdown()
}

That's it, we're done! If you have any questions, please leave a comment.

Tuesday, December 18, 2012

sprouch tutorial - basics

In this tutorial I will show you how to add the sprouch library to your project and use it to create, read, update and delete documents in CouchDB (or BigCouch or Cloudant). The source code is available at github.com/KimStebel/sprouch-tutorial.

This tutorial is written for Scala 2.9, but you can also use 2.10. Here is the build.sbt file:


name := "sprouch-tutorial"

scalaVersion := "2.9.2"

Sprouch is available from its own repository on github, so you need to add it to your resolvers.


resolvers += "sprouch repo" at
             "http://kimstebel.github.com/sprouch/repository"

Now sbt will be able to resolve our dependency on sprouch.


libraryDependencies += "sprouch" % "sprouch_2.9.2" % "0.5.7"

If you want to use 2.10, just replace 2.9.2 with 2.10.

Now to the actual code. First you need a few imports: sprouch contains the main classes Couch and Database. sprouch.dsl contains implicit conversions that allow you to use a shorter, more convenient syntax. Finally, sprouch.JsonProtocol contains methods to convert Scala types from and to JSON.


object Main extends App {
  import sprouch._
  import sprouch.dsl._
  import sprouch.JsonProtocol._

Suppose you have a Scala class used to represent products in an online store.


  case class ShopItem(
      name: String,
      price: BigDecimal,
      description:Option[String])

You would like to store it in CouchDB. Since CouchDB stores its data as JSON documents, you first need a way to convert products to and from JSON. Since you defined ShopItem as a case class, there is an easy way to do this. You call jsonFormat3(ShopItem) to get a JsonFormat[ShopItem]. JsonFormat is a just trait with a read and a write method, so you can easily implement one yourself if needed.


  implicit val productFormat = jsonFormat3(ShopItem)

Now you need to connect to CouchDB. First you create a Config object. The config object takes an ActorSystem and any configuration settings needed to connect to CouchDB. In this tutorial, an actor system is created just to pass it to Sprouch. In a real application you will probably already have one configured. If you don't specify any other parameters, sprouch assumes CouchDB is running on localhost, port 5894, does not require a username or password and uses HTTP and not HTTPS.


  import akka.actor.ActorSystem
  val actorSystem = ActorSystem("myActorSystem")
  val config = Config(actorSystem)

Here is a different configuration that would work with cloudant.


  val config2 = Config(
      actorSystem,
      hostName="someone.cloudant.com",
      port=443,
      userPass=Some("someone" -> "password"),
      https=true
  )

Then we create a new couch object with this config.


  val couch = Couch(config)

Now comes the interesting part. You get a reference to the items database or create it, if it does not already exist. You make the val implicit so you don't have to pass it to every method that creates/reads/updates documents in the database.


  implicit val db = couch.getDb("items") recoverWith { case _ =>
    couch.createDb("items")
  }

You create a new product to put into our database


  val phone = ShopItem("Samsung S5", 500, Some("Shiny new smartphone"))

Since Sprouch is an asynchronous library, all its methods return futures. You can use a for comprehension to chain these futures together.


  val future = for {

First you add the phone to the database.


    phoneDoc <- phone.create

The create method gives us a RevedDocument[ShopItem]. The RevedDocument contains an automatically generated ID (you canalso pass your own ID to create), the document revision returned by CouchDB and of course the phone object. Let's say you want to reduce the phone's price. Since you have a case class, you can use its copy method to update the price and the description.


    reduced = phone.copy(
        price = 400,
        description = Some("Shiny new smartphone. Now 20% off!")
    )

Then you persist the changes in the database.


    updatedPhoneDoc <- phoneDoc := reduced

To read a document, there are several options. If you already have a document and just want to get the most recent revision, you can pass the old document to the get method.


    latest <- get(phoneDoc)

Or you can get the document by its ID. In this case you have to specify the type of the document.


    byId <- get[ShopItem](phoneDoc.id)

If you don't want to sell this phone anymore, you can delete it from the database. Note that you need to have the latest version of the document, because deletion will fail if the revision is not current.


    _ <- latest.delete

This outputs the first and second version of the phone document.


  } yield {
    println("First version: " + phoneDoc)
    println("Second version: " + updatedPhoneDoc)
  }

The output is

First version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 1-3ef3ac1b402f0948d2a94a383708dcda,
    data: ShopItem(Samsung S5,500,Some(Shiny new smartphone)))
Second version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 2-9e8f214f19641582c22b09bf6fab8141,
    data: ShopItem(Samsung S5,400,Some(Shiny new smartphone.
                                       Now 20% off!)))
       

Finally you wait for the result to be computed. Again, this is something you probably don't want to do in a real application. If you want your methods to block, you can use Sprouch's synchronous API.


  import akka.util.Duration
  import akka.dispatch.Await
  val duration = Duration("10 seconds")
  Await.result(future, duration)
  actorSystem.shutdown()
}

That's it, you're done! If you have any questions, please leave a comment.