2019/12/03
GraphQL Transformの @versioned
というディレクティブについて動作を確認した
この @versioned
がついたtypeは自動でversionというカラムが定義され、update時にインクリメントされる。
type Post @model @versioned {
id: ID!
title: String!
}
{
"id": "7d89e225-7659-4bb4-816a-f23c659c8d0c",
"title": "こんにちは",
"version": 1
}
また、update時に変更するversionを渡し(例の場合はversionが2になる)、更新時にversionに差異があった場合は更新処理を弾くようになる。
これは、DynamoDBのロック手法でAWSが上げているオプティミスティックロック(楽観的ロック、楽観的排他制御とも呼ばれる)をAmplifyで実現するための機能になっている。
コンパイルされたVTLを参照すると、上記リンクと同様にDynamoDBの条件付き更新を使って、バージョンの比較をしていることがわかる。
## [Start] Inject @versioned condition.. **
#set( $versionedCondition = {
"expression": "#version = :expectedVersion",
"expressionValues": {
":expectedVersion": $util.dynamodb.toDynamoDB($ctx.args.input.expectedVersion)
},
"expressionNames": {
"#version": "version"
}
} )
#set( $newVersion = $ctx.args.input.expectedVersion + 1 )
$util.qr($ctx.args.input.put("version", $newVersion))
$util.qr($ctx.args.input.remove("expectedVersion"))
## [End] Inject @versioned condition.. **
## ~~~
## Update condition if type is @versioned **
#if( $versionedCondition )
$util.qr($condition.put("expression", "($condition.expression) AND $versionedCondition.expression"))
$util.qr($condition.expressionNames.putAll($versionedCondition.expressionNames))
$util.qr($condition.expressionValues.putAll($versionedCondition.expressionValues))
#end
## ~~~
Amplify, GraphQL Transform に限らず、DynamoDBを扱う上での楽観的ロックの手法は覚えておいて損はなさそう。