2019/12/03

GraphQL Transform

GraphQL Transformの @versionedというディレクティブについて動作を確認した

この @versioned がついたtypeは自動でversionというカラムが定義され、update時にインクリメントされる。

定義したschema.graphql

type Post @model @versioned {
  id: ID!
  title: String!
}

生成されたDynamoDBのデータ例

{
  "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を扱う上での楽観的ロックの手法は覚えておいて損はなさそう。