[GitHub Copilot] DynamoDBテーブル上のデータをSDKで操作する関数を作成してみた

2023.03.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 Delivery部の若槻です。

前回のエントリではGitHub CopilotをVisual Studio Codeに導入するところまでやってみました。

今回は実践編として、GitHub Copilotに頼りながらDynamoDBテーブル上のデータをSDKで操作する関数(TypeScript)を作成してみました。

やってみた

SDKのインポート

まずAWS SDK for JavaScript v3をインポートする記述です。

script.ts

// DynamoDBテーブルをクエリする
// AWS SDK for JavaScript v3をインポート
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';

ポイント

  • 冒頭でDynamoDBテーブルをクエリする旨を宣言することにより、次行以降でクエリに必要なモジュールのみがインポートされる。
  • AWS SDK for JavaScript v3をインポートしたいことを明示的に記述しなければv2のインポート文がサジェストされてしまう。

DynamoDBクライアント作成

次にインポートしたSDKを使用してDynamoDBクライアントを作成します。

script.ts

// DynamoDBテーブルをクエリする
// AWS SDK for JavaScript v3をインポート
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';
// DynamoDBクライアントを作成
const client = new DynamoDBClient({ region: 'ap-northeast-1' });

ポイント

  • コメント行で改行後にコードのサジェストがされない場合は、想定されるコードの書き出しを記述してあげることにより候補が出るようになる。

ユーザー型の定義

テーブル上に保管されるユーザーデータの型を定義します。

script.ts

// DynamoDBテーブルをクエリする
// AWS SDK for JavaScript v3をインポート
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';
// DynamoDBクライアントを作成
const client = new DynamoDBClient({ region: 'ap-northeast-1' });

// ユーザー型を定義
type User = {
  id: string;
  name: string;
  age: number;
};

ポイント

  • 型名をもとにそれらしい内容の型を自動で生成してくれるので、必要に応じて修正する。

クエリ実行する関数の作成

最後に、DynamoDBテーブルをクエリする処理を記述します。

script.ts

// DynamoDBテーブルをクエリする
// AWS SDK for JavaScript v3をインポート
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';
// DynamoDBクライアントを作成
const client = new DynamoDBClient({ region: 'ap-northeast-1' });

// ユーザー型を定義
type User = {
  id: string;
  name: string;
  age: number;
};

// ユーザーをクエリしてユーザーリストを返す
export const queryUsers = async (): Promise<User[]> => {
  const params = {
    TableName: 'Users',
    KeyConditionExpression: 'id = :id',
    ExpressionAttributeValues: {
      ':id': { S: '1' },
    },
  };
  const command = new QueryCommand(params);
  const data = await client.send(command);
  // プロパティ値がundefinedの場合は空文字列に置き換える
  const users = data.Items?.map((item) => ({
    id: item.id.S ?? '',
    name: item.name.S ?? '',
    age: item.age.N ? parseInt(item.age.N) : 0,
  }));
  // ユーザーリストを返す
  return users ?? [];
};

ポイント

  • ユーザーをクエリするというコメントだけだと単一のユーザーデータを返す関数を作ろうとするため、ユーザーをクエリしてユーザーリストを返すまで記述してあげる必要があった。
  • 関数の中身は一気にサジェストして記述してくれますが、戻り値のデータでロパティ値がundefinedの場合が考慮されていないためタイプエラーとなった。エラーとなっている記述を消して明示的にプロパティ値がundefinedの場合は空文字列に置き換えるという記述をしたら対応するコードをサジェストしてくれた。

引数としてクエリキーを受け取るようにする

引数としてクエリキーとなるidを受け取るようにし、クエリで使用するように修正します。

script.ts

// DynamoDBテーブルをクエリする
// AWS SDK for JavaScript v3をインポート
import { DynamoDBClient, QueryCommand } from '@aws-sdk/client-dynamodb';
// DynamoDBクライアントを作成
const client = new DynamoDBClient({ region: 'ap-northeast-1' });

// ユーザー型を定義
type User = {
  id: string;
  name: string;
  age: number;
};

// ユーザーをクエリしてユーザーリストを返す
// 引数としてユーザーIDを受け取る
export const queryUser = async (id: string): Promise<User[]> => {
  // DynamoDBクエリを作成
  const command = new QueryCommand({
    TableName: 'users',
    KeyConditionExpression: 'id = :id',
    ExpressionAttributeValues: {
      ':id': { S: id },
    },
  });
  // DynamoDBクエリを実行
  const result = await client.send(command);
  // ユーザーリストを作成
  const users: User[] = [];
  // レスポンスからユーザーを抽出
  // レスポンスのItemsはundefinedかItemの配列
  // Type 'string | undefined' is not assignable to type 'string'. を考慮
  if (result.Items) {
    for (const item of result.Items) {
      const user: User = {
        id: item.id.S || '',
        name: item.name.S || '',
        age: item.age.N ? parseInt(item.age.N) : 0,
      };
      users.push(user);
    }
  }
  return users;
};
  • 引数としてユーザーIDを受け取るのようにコメントを追加すれば、その通りに関数を作ってくれた。
  • クエリキーを関数の引数として受け取るように変更しようとしただけですが、再度全体のコードをサジェストしてもらっためクエリ結果をパースする処理がかなり変わってしまった。
  • サジェストされたコードでエラーが発生している場合はそのエラーメッセージをコメントを記述すれば、考慮したコードを再度サジェストしてくれる。

おわりに

GitHub Copilotに頼りながらDynamoDBテーブル上のデータをSDKで操作する関数(TypeScript)を作成してみました。

コメントで要求を書くとコードをサジェストしてくれる体験はすごく面白いですが、サジェストのされ方に癖があったり試行毎にサジェスト内容が変わるため、欲しいコードを引き出すために若干のコツが必要だという印象を受けました。

今回は単一のモジュール上でのCopilotの動作を試しましたが、次回は複数のモジュールにまたがる場合の動作を試してみたいと思います。

以上