Skip to content

Commit

Permalink
More docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Wills committed Dec 6, 2016
1 parent a2b419b commit 8079734
Show file tree
Hide file tree
Showing 10 changed files with 260 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ scala> import cats.syntax.either._

scala> val client = LocalDynamoDB.client()
scala> import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
scala> val farmersTableResult = LocalDynamoDB.createTable(client)("winners")('name -> S)
scala> val winnersTableResult = LocalDynamoDB.createTable(client)("winners")('name -> S)

scala> case class LuckyWinner(name: String, shape: String)
scala> def temptWithGum(child: LuckyWinner): LuckyWinner = child match {
Expand Down
22 changes: 20 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ testOptions in Test += dynamoDBLocalTestCleanup.value

tut := tut.dependsOn(startDynamoDBLocal).value

lazy val buildMicrosite = taskKey[Unit]("make the microsite and cleanup local DynamoDB afterwards")
buildMicrosite := Def.sequential(makeMicrosite.toTask, stopDynamoDBLocal.toTask).value
tut <<= (tut, stopDynamoDBLocal){ (tut, stop) => tut.doFinally(stop)}

enablePlugins(MicrositesPlugin)

Expand Down Expand Up @@ -105,3 +104,22 @@ releaseProcess := Seq[ReleaseStep](
ReleaseStep(action = Command.process("sonatypeReleaseAll", _)),
pushChanges
)

micrositeName := "Scanamo"
micrositeDescription := "Scanamo: simpler DynamoDB access for Scala"
micrositeAuthor := "Phil Wills"
micrositeGithubOwner := "guardian"
micrositeGithubRepo := "scanamo"
micrositeBaseUrl := ""
micrositeDocumentationUrl := "/scanamo/latest/api"
micrositeHighlightTheme := "color-brewer"
micrositePalette := Map(
"brand-primary" -> "#951c55",
"brand-secondary" -> "#005689",
"brand-tertiary" -> "#00456e",
"gray-dark" -> "#453E46",
"gray" -> "#837F84",
"gray-light" -> "#E3E2E3",
"gray-lighter" -> "#F4F3F4",
"white-color" -> "#FFFFFF"
)
20 changes: 20 additions & 0 deletions src/main/resources/microsite/data/menu.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
options:
- title: Put and Get
url: put-get.html
menu_section: operations

- title: Querying
url: querying.html
menu_section: operations

- title: Updating
url: updating.html
menu_section: operations

- title: Using Indexes
url: using-indexes.html
menu_section: home

- title: Asynchronous Requests
url: asynchronous.html
menu_section: home

- title: Custom Formats
url: custom-formats.html
menu_section: home
40 changes: 40 additions & 0 deletions src/main/tut/asynchronous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
layout: docs
title: Asynchronous Requests
position: 7
---

### Non-blocking requests

Whilst for simplicity most examples in these documents are based on synchronous
requests to DynamoDB, Scanamo supports making the requests asynchronously with
a client that implements the `AmazonDynamoDBAsync` interface:

```tut:silent
import com.gu.scanamo._
import com.gu.scanamo.syntax._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
LocalDynamoDB.createTable(client)("farm")('name -> S)
case class Farm(animals: List[String])
case class Farmer(name: String, age: Long, farm: Farm)
val farmTable = Table[Farmer]("farm")
val ops = for {
_ <- farmTable.putAll(Set(
Farmer("Boggis", 43L, Farm(List("chicken"))),
Farmer("Bunce", 52L, Farm(List("goose"))),
Farmer("Bean", 55L, Farm(List("turkey")))
))
bunce <- farmTable.get('name -> "Bunce")
} yield bunce
```
```tut:book
//concurrent.Await.result(ScanamoAsync.exec(client)(ops), 5.seconds)
```

Note that `AmazonDynamoDBAsyncClient` uses a thread pool internally.
40 changes: 40 additions & 0 deletions src/main/tut/custom-formats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
layout: docs
title: Custom Formats
position: 5
---

### Custom Formats

Scanamo uses the `DynamoFormat` type class to define how to read and write
different types to DynamoDB. Scanamo provides such formats for many common
types, but it's also possible to define a serialisation format for types
which Scanamo doesn't provide. For example to store Joda `DateTime` objects
as ISO `String`s in Dynamo:

```tut:silent
import org.joda.time._
import com.gu.scanamo._
import com.gu.scanamo.syntax._
case class Foo(dateTime: DateTime)
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
LocalDynamoDB.createTable(client)("foo")('dateTime -> S)
```
```tut:book
implicit val jodaStringFormat = DynamoFormat.coercedXmap[DateTime, String, IllegalArgumentException](
DateTime.parse(_).withZone(DateTimeZone.UTC)
)(
_.toString
)
val fooTable = Table[Foo]("foo")
val operations = for {
_ <- fooTable.put(Foo(new DateTime(0)))
results <- fooTable.scan()
} yield results
Scanamo.exec(client)(operations).toList
```
36 changes: 36 additions & 0 deletions src/main/tut/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
---
layout: home
section: home
position: 1
---

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.gu/scanamo_2.11/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.gu/scanamo_2.12) [![Build Status](https://travis-ci.org/guardian/scanamo.svg?branch=master)](https://travis-ci.org/guardian/scanamo) [![Coverage Status](https://coveralls.io/repos/github/guardian/scanamo/badge.svg?branch=master)](https://coveralls.io/github/guardian/scanamo?branch=master) [![Chat on gitter](https://badges.gitter.im/guardian/scanamo.svg)](https://gitter.im/guardian/scanamo)

Scanamo is a library to make using [DynamoDB](https://aws.amazon.com/documentation/dynamodb/) with Scala
simpler and less error-prone.

The main focus is on making it easier to avoid mistakes and typos by leveraging Scala's type system and some
higher level abstractions.

Quick start
-----------

Scanamo is published for Scala 2.11 and 2.12 to Maven Central, so just add the following to your `build.sbt`:

```scala
libraryDependencies ++= Seq(
"com.gu" %% "scanamo" % "0.8.1"
)
```

then, given a table and some case classes

```tut:silent
import com.gu.scanamo._
import com.gu.scanamo.syntax._
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
val farmersTableResult = LocalDynamoDB.createTable(client)("farmer")('name -> S)
case class Farm(animals: List[String])
case class Farmer(name: String, age: Long, farm: Farm)
```
we can simply `put` and `get` items from Dynamo, without boilerplate or reflection

```tut:book
val table = Table[Farmer]("farmer")
Scanamo.exec(client)(table.put(Farmer("McDonald", 156L, Farm(List("sheep", "cow")))))
Scanamo.exec(client)(table.get('name -> "McDonald"))
```

Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
34 changes: 34 additions & 0 deletions src/main/tut/put-get.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
layout: docs
title: Putting and Getting
position: 2
---

### Putting and Getting

Often when using DynamoDB, the primary use case is simply putting objects into
Dynamo and subsequently retrieving them:

```tut:silent
import com.gu.scanamo._
import com.gu.scanamo.syntax._
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
LocalDynamoDB.createTable(client)("muppets")('name -> S)
case class Muppet(name: String, species: String)
```
```tut:book
val muppets = Table[Muppet]("muppets")
val operations = for {
_ <- muppets.put(Muppet("Kermit", "Frog"))
_ <- muppets.put(Muppet("Cookie Monster", "Monster"))
_ <- muppets.put(Muppet("Miss Piggy", "Pig"))
kermit <- muppets.get('name -> "Kermit")
} yield kermit
Scanamo.exec(client)(operations)
```

Note that when using `Table` no operations are actually executed against DynamoDB until `exec` is called.
6 changes: 4 additions & 2 deletions src/main/tut/querying.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
layout: docs
title: Querying
position: 3
---

### Querying
Expand All @@ -13,7 +14,8 @@ import com.gu.scanamo.syntax._
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
val transportTableResult = LocalDynamoDB.createTable(client)("transports")('mode -> S, 'line -> S)
LocalDynamoDB.createTable(client)("transports")('mode -> S, 'line -> S)
case class Transport(mode: String, line: String)
val transportTable = Table[Transport]("transports")
val operations = for {
Expand All @@ -25,7 +27,7 @@ val operations = for {
tubesStartingWithC <- transportTable.query('mode -> "Underground" and ('line beginsWith "C"))
} yield tubesStartingWithC.toList
```
```tut
```tut:book
Scanamo.exec(client)(operations)
```

29 changes: 29 additions & 0 deletions src/main/tut/updating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
layout: docs
title: Updating
position: 4
---

### Updating

If you want to update some of the fields of a row, which don't form part of the key,
without replacing it entirely, you can use the `update` operation:

```tut:silent
import com.gu.scanamo._
import com.gu.scanamo.syntax._
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
val teamTableResult = LocalDynamoDB.createTable(client)("teams")('name -> S)
case class Team(name: String, goals: Int, scorers: List[String], mascot: Option[String])
val teamTable = Table[Team]("teams")
val operations = for {
_ <- teamTable.put(Team("Watford", 1, List("Blissett"), Some("Harry the Hornet")))
updated <- teamTable.update('name -> "Watford",
set('goals -> 2) and append('scorers -> "Barnes") and remove('mascot))
} yield updated
```
```tut:book
Scanamo.exec(client)(operations)
```
36 changes: 36 additions & 0 deletions src/main/tut/using-indexes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
layout: docs
title: Using Indexes
position: 6
---

### Using Indexes

Scanamo supports scanning and querying [global secondary indexes](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html).
In the following example, we create and use a table called `transport` with a hash key
of `mode` and range key of `line` and a global secondary called `colour-index`
with only a hash key on the `colour` attribute:

```tut:silent
import com.gu.scanamo._
import com.gu.scanamo.syntax._
case class Transport(mode: String, line: String, colour: String)
val transport = Table[Transport]("transport")
val colourIndex = transport.index("colour-index")
val client = LocalDynamoDB.client()
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType._
```
```tut:book
LocalDynamoDB.withTableWithSecondaryIndex(client)("transport", "colour-index")('mode -> S, 'line -> S)('colour -> S) {
val operations = for {
_ <- transport.putAll(Set(
Transport("Underground", "Circle", "Yellow"),
Transport("Underground", "Metropolitan", "Maroon"),
Transport("Underground", "Central", "Red")))
maroonLine <- colourIndex.query('colour -> "Maroon")
} yield maroonLine.toList
Scanamo.exec(client)(operations)
}
```

0 comments on commit 8079734

Please sign in to comment.