Skip to content
This repository has been archived by the owner on Sep 27, 2021. It is now read-only.

docs: batched ops, conditionals, etc #183

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion vuepress/docs/docs/basic-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Let's use it to remove a particular score from the ladder:
table.deleteItem(mainFullKey(userId))
```

Okay, in this section we finally discovered how to make queries with D4S and before we go to know for other operation and possibilities
Okay, in this section we finally discovered how to make queries with D4S and before we go to know for other operations and possibilities
that D4S provides, we would like to highlight what we've learnt so far:
- we able to setup project with D4S
- we able to define a table
Expand Down
74 changes: 73 additions & 1 deletion vuepress/docs/docs/batched-operations.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,74 @@
# Batched operations
coming soon

Sometimes we need to work with a large amount of data. Using standard operations like `put`/`update`/`delete`
to modify data in a database could affect system performance. Fortunately, AWS team implement batch operations
for DynamoDB.

So, in case we want to `delete` records for several users from leaderboard table, we could do this by typing
the following:
```scala
val usersToDelete: List[UserId] = ...
connector.run("batch-delete") {
table.deleteItemBatch(usersToDelete.map(mainFullKey))
}
```
_Important note_: `deleteItemBatch` operation requires implicit `D4SEncoder` that converts user's concrete type
to `Map[String, AttributeValue]`. Here we take a slightly different way. Leaderbord table has simple key that contains
user's UUID only. In table definition we described a helper function `mainFullKey` that encodes `UserId` for use:
```scala
def mainFullKey(value: UserId): Map[String, AttributeValue] = {
mainKey.bind(userId.value)
}
```
Alternatively, you can handle this by extending abstract class WithD4S which provides codecs for you:
```scala
final case class UserId(id: UUID) extends AnyVal
object UserId extends WithD4S[UserId]

```

Now, let's say we want to get scores of players that are on the same team. We can use `getItemBatch` combinator
to achieve this:
```scala
val team: List[UserId] = ...
connector.run("get-team-members-scores") {
table.getItemBatch(usersToDelete.map(mainFullKey))
}
```
That's it!!! Basically, the code is the same in both cases (get/delete), the only difference is type of operation we want to
execute. Same thing applies for `put` operation. We can easily insert a new data with `putItemBatch` combinator.
Be aware, that for this operation you need to specify all attributes e.g.
```scala
final case class UserWithScore(id: UserId, score: Long)
object UserWithScore extends WithD4S[UserWithScore]

val data: List[UserWithScore] = ...
connector.run("write-batch") {
table.putItemBatch(data)
}
```
Note, that all `d4s` batched operations handles pagination by default, so you can sleep well at night :).
One thing has been uncovered by us so far. It's combinators that built on top of DynamoDB operations.
Sometimes we perform queries that could be described using several DynamoDB operations sequentially.
In our production experience we found `query-delete` patter very common, so we provide convenient combinator
`queryDeleteBatch` for that. Imagine that we want to deliver a prize for players that won our game's tournament or
finished a hard level with a high score.
Obviously, we need to have a separate table for that purpose. In that case table's key will have hash and range part,
user's UUID and prize UUID respectively. Let's say the user collect his prizes thus we have no need to store them.
Here is how we can remove all prized granted to a specific user using `queryDeleteBatch`:
```scala
def deletePackages(user: UserId) = {
connector.run("remove-prizes) {
table
.queryDeleteBatch
.withKey(prizesTable.key.bind(user.id))
}
}
```
The query above fetches all recs that has hash key equal to specified id and then in parallel fashion deletes data chunks
using Dynamo's batch write operation.
Note: we omit table definition here because we've already known how to do this. `prizesTable` has a `key` of type `DynamoKey`.
`DynamoKey` type has bind method that helps us convert concrete type to `Map[String, AttributeValue]`.

Okay, that all. Now you know how to perform batched operation with d4s and ready to use it on the battleground.
In the next section we will learn more about conditionals.