dynamodb-toolbox-patterns
DynamoDB-Toolbox v2 を使用した TypeScript パターンを提供します。スキーマ・テーブル・エンティティのモデリング、`.build()` コマンドワークフロー、クエリ/スキャンのアクセスパターン、バッチ・トランザクション操作、computed keys を活用したシングルテーブル設計などを網羅しています。TypeScript サービスやサーバーレスアプリケーションで DynamoDB-Toolbox v2 による型安全な DynamoDB アクセス層を実装する際に使用してください。
description の原文を見る
Provides TypeScript patterns for DynamoDB-Toolbox v2 including schema/table/entity modeling, .build() command workflow, query/scan access patterns, batch and transaction operations, and single-table design with computed keys. Use when implementing type-safe DynamoDB access layers with DynamoDB-Toolbox v2 in TypeScript services or serverless applications.
SKILL.md 本文
DynamoDB-Toolbox v2 Patterns (TypeScript)
概要
このスキルは、AWS SDK v3 DocumentClient を使用した DynamoDB-Toolbox v2 の実践的な TypeScript パターンを提供します。タイプセーフなスキーマモデリング、.build() コマンドの使用法、本番対応のシングルテーブル設計に焦点を当てています。
使用場面
- 厳密な TypeScript 型推論でDynamoDB テーブルとエンティティを定義する
item、string、number、list、set、map、recordを使用したスキーマモデリング.build()経由でGetItem、PutItem、UpdateItem、DeleteItemを実装する- プライマリキーと GSI を使用したクエリおよびスキャンアクセスパスを構築する
- バッチ操作とトランザクション操作を処理する
- 計算キーとエンティティパターンを使用したシングルテーブルシステムを設計する
使用方法
- アクセスパターンから開始する: まずは読み書きクエリを特定し、その後キーを設計します。
- テーブルとエンティティの境界を作成する: 1 つのテーブル、シングルテーブル設計を使用する場合は複数のエンティティです。
- 制約を付けてスキーマを定義する:
.key()、.required()、.default()、.transform()、.link()を適用します。 - すべての場所で
.build()コマンドを使用する: 一貫性と型安全性のためにアドホックなコマンド構築を避けます。 - クエリ/インデックスカバレッジを追加する: 必要な各アクセスパターンに対して GSI/LSI パスを検証します。
- バッチ/トランザクションを意図的に使用する: スループットはバッチ、原子性はトランザクション。
- アイテムを進化させやすくする: スキーマ進化のためにオプショナルフィールド、デフォルト値、派生属性を使用します。
例
インストールと設定
npm install dynamodb-toolbox @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { Table } from 'dynamodb-toolbox/table';
import { Entity } from 'dynamodb-toolbox/entity';
import { item, string, number, list, map } from 'dynamodb-toolbox/schema';
const client = new DynamoDBClient({ region: process.env.AWS_REGION ?? 'eu-west-1' });
const documentClient = DynamoDBDocumentClient.from(client);
export const AppTable = new Table({
name: 'app-single-table',
partitionKey: { name: 'PK', type: 'string' },
sortKey: { name: 'SK', type: 'string' },
indexes: {
byType: { type: 'global', partitionKey: { name: 'GSI1PK', type: 'string' }, sortKey: { name: 'GSI1SK', type: 'string' } }
},
documentClient
});
修飾子と複雑な属性を持つエンティティスキーマ
const now = () => new Date().toISOString();
export const UserEntity = new Entity({
name: 'User',
table: AppTable,
schema: item({
tenantId: string().required('always'),
userId: string().required('always'),
email: string().required('always').transform(input => input.toLowerCase()),
role: string().enum('admin', 'member').default('member'),
loginCount: number().default(0),
tags: list(string()).default([]),
profile: map({
displayName: string().optional(),
timezone: string().default('UTC')
}).default({ timezone: 'UTC' })
}),
computeKey: ({ tenantId, userId }) => ({
PK: `TENANT#${tenantId}`,
SK: `USER#${userId}`,
GSI1PK: `TENANT#${tenantId}#TYPE#USER`,
GSI1SK: `EMAIL#${userId}`
})
});
.build() CRUD コマンド
import { PutItemCommand } from 'dynamodb-toolbox/entity/actions/put';
import { GetItemCommand } from 'dynamodb-toolbox/entity/actions/get';
import { UpdateItemCommand, $add } from 'dynamodb-toolbox/entity/actions/update';
import { DeleteItemCommand } from 'dynamodb-toolbox/entity/actions/delete';
await UserEntity.build(PutItemCommand)
.item({ tenantId: 't1', userId: 'u1', email: 'A@Example.com' })
.send();
const { Item } = await UserEntity.build(GetItemCommand)
.key({ tenantId: 't1', userId: 'u1' })
.send();
await UserEntity.build(UpdateItemCommand)
.item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
.send();
await UserEntity.build(DeleteItemCommand)
.key({ tenantId: 't1', userId: 'u1' })
.send();
クエリとスキャンパターン
import { QueryCommand } from 'dynamodb-toolbox/table/actions/query';
import { ScanCommand } from 'dynamodb-toolbox/table/actions/scan';
const byTenant = await AppTable.build(QueryCommand)
.query({
partition: `TENANT#t1`,
range: { beginsWith: 'USER#' }
})
.send();
const byTypeIndex = await AppTable.build(QueryCommand)
.query({
index: 'byType',
partition: 'TENANT#t1#TYPE#USER'
})
.options({ limit: 25 })
.send();
const scanned = await AppTable.build(ScanCommand)
.options({ limit: 100 })
.send();
バッチおよびトランザクションワークフロー
import { BatchWriteCommand } from 'dynamodb-toolbox/table/actions/batchWrite';
import { TransactWriteCommand } from 'dynamodb-toolbox/table/actions/transactWrite';
await AppTable.build(BatchWriteCommand)
.requests(
UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u2', email: 'u2@example.com' }),
UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u3', email: 'u3@example.com' })
)
.send();
await AppTable.build(TransactWriteCommand)
.requests(
UserEntity.build(PutItemCommand).item({ tenantId: 't1', userId: 'u4', email: 'u4@example.com' }),
UserEntity.build(UpdateItemCommand).item({ tenantId: 't1', userId: 'u1', loginCount: $add(1) })
)
.send();
シングルテーブル設計ガイダンス
- 各ビジネスコンセプトをエンティティとして厳密なスキーマでモデル化します。
- PK/SK を予測可能かつ合成可能に保つ (
TENANT#、USER#、ORDER#)。 - アクセスパスを GSI キーにエンコードし、メモリ内フィルターには使用しません。
- 監査/履歴データに対してはアペンドのみのタイムラインを推奨します。
- スコープ付きパーティションとシャーディングで必要に応じてホットパーティションを管理します。
ベストプラクティス
- アクセスパターンからキー設計を先に行い、その後エンティティ属性を導出します。
- キーの合成の単一の情報源 (
computeKey) を維持して、ドリフトを防ぎます。 - 厳密な読み書き後の一貫性が必要な場合のみ
.options({ consistent: true })を使用します。 - リクエストパスではスキャンより対象を絞ったクエリを推奨します。
- べき等性と楽観的同時実行制御のために条件式を追加します。
- 部分的な失敗を避けるため、実行前にバッチ/トランザクションサイズ制限を検証します。
制約および警告
- DynamoDB-Toolbox v2 は AWS SDK v3 DocumentClient 統合に依存します。
- 明示的に制限されていない限り、リクエストパスでテーブルスキャンを避けます。
- 同時実行性に敏感な更新に対して条件付き書き込みを使用します。
- トランザクションには制限があり、シングルアイテム書き込みより遅いため、真の原子性の要件がある場合のみ使用します。
- 実装前に目標スループットに対してキー設計を検証します。
参考資料
Context7 から選別された主要な参考資料は以下で利用可能です:
references/api-dynamodb-toolbox-v2.md
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。