Type-safe DynamoDB client wrapper with single-table design utilities for fnd-platform
npm install @fnd-platform/dynamodbType-safe DynamoDB client wrapper with single-table design utilities, entity definitions, and key builders for fnd-platform applications.
``bash`
npm install @fnd-platform/dynamodbor
pnpm add @fnd-platform/dynamodb
`typescript
import { FndDynamoDB, EntityRepository, UserEntity, keys } from '@fnd-platform/dynamodb';
// Create client
const db = new FndDynamoDB({ tableName: 'my-table' });
// Create repository for User entity
const userRepo = new EntityRepository(db, UserEntity);
// Create a user
const user = await userRepo.create({
email: 'john@example.com',
name: 'John Doe',
role: 'admin',
});
// Query using key builders
const profile = await db.get({
pk: keys.user.pk(user.id),
sk: keys.user.sk.profile(),
});
`
- Type-Safe Client - Full TypeScript support with automatic type inference
- Entity System - Define entities with automatic key generation and timestamps
- Key Builders - Type-safe key generation for single-table design
- Query Helpers - Pre-built query patterns for common access patterns
- Expression Builders - Utilities for update and condition expressions
`typescript
import { FndDynamoDB } from '@fnd-platform/dynamodb';
const db = new FndDynamoDB({
tableName: process.env.TABLE_NAME!,
// Optional: custom DynamoDB client options
});
`
`typescript
import { defineEntity } from '@fnd-platform/dynamodb';
const ProductEntity = defineEntity({
name: 'Product',
keyConfig: {
pk: (ctx) => PRODUCT#${ctx.id},CATEGORY#${ctx.category}
sk: () => 'METADATA',
},
gsiConfig: {
GSI1: {
pk: (ctx) => ,PRODUCT#${ctx.id}
sk: (ctx) => ,`
},
},
attributes: {
name: { type: 'string', required: true },
price: { type: 'number', required: true },
category: { type: 'string', required: true },
description: { type: 'string' },
},
});
`typescript
import { EntityRepository } from '@fnd-platform/dynamodb';
const productRepo = new EntityRepository(db, ProductEntity);
// Create
const product = await productRepo.create({
name: 'Widget',
price: 29.99,
category: 'gadgets',
});
// Get by ID
const found = await productRepo.get(product.id);
// Update
const updated = await productRepo.update(product.id, {
price: 24.99,
});
// Delete
await productRepo.delete(product.id);
// Query
const products = await productRepo.query({
indexName: 'GSI1',
pk: CATEGORY#gadgets,`
});
`typescript
import { UserEntity, type User, type UserRole } from '@fnd-platform/dynamodb';
// UserRole: 'admin' | 'editor' | 'viewer'
const userRepo = new EntityRepository(db, UserEntity);
`
`typescript
import { ContentEntity, type Content, type ContentStatus } from '@fnd-platform/dynamodb';
// ContentStatus: 'draft' | 'published' | 'archived'
const contentRepo = new EntityRepository(db, ContentEntity);
`
`typescript
import { MediaEntity, type Media } from '@fnd-platform/dynamodb';
const mediaRepo = new EntityRepository(db, MediaEntity);
`
`typescript
import { keys } from '@fnd-platform/dynamodb';
// User keys
keys.user.pk('user-123'); // 'USER#user-123'
keys.user.sk.profile(); // 'PROFILE'
keys.user.sk.post('post-456'); // 'POST#post-456'
// Content keys
keys.content.pk('content-123'); // 'CONTENT#content-123'
keys.content.sk.draft(); // 'v#draft'
keys.content.sk.published(); // 'v#published'
keys.content.gsi1.bySlug('my-post'); // { GSI1PK: 'CONTENT#SLUG#my-post', GSI1SK: 'CONTENT' }
// Media keys
keys.media.pk('media-123'); // 'MEDIA#media-123'
`
`typescript
import { ContentQueries, UserQueries, MediaQueries } from '@fnd-platform/dynamodb';
// Content queries
const contentQueries = new ContentQueries(db);
const post = await contentQueries.getBySlug('my-post');
const published = await contentQueries.listPublished({ limit: 10 });
const byType = await contentQueries.listByType('blog-post', { status: 'published' });
// User queries
const userQueries = new UserQueries(db);
const admins = await userQueries.listByRole('admin');
// Media queries
const mediaQueries = new MediaQueries(db);
const images = await mediaQueries.listByContentType('image/*');
`
`typescript
import { createQueryBuilder } from '@fnd-platform/dynamodb';
const results = await createQueryBuilder(db)
.index('GSI1')
.pk('CATEGORY#gadgets')
.skBeginsWith('PRODUCT#')
.filter('price', '<', 50)
.limit(20)
.execute();
`
See the full API documentation for detailed type definitions and examples.
- FndDynamoDB - Main DynamoDB client classFndDynamoDBConfig
- - Client configuration type
`typescript`
import {
defineEntity, // Define a new entity
EntityRepository, // CRUD operations for entities
// Validation utilities
validateBaseEntity,
validateKeys,
isValidTimestamp,
isEntity,
} from '@fnd-platform/dynamodb';
`typescript`
import { UserEntity, ContentEntity, MediaEntity } from '@fnd-platform/dynamodb';
`typescript`
import { keys } from '@fnd-platform/dynamodb';
`typescript`
import { ContentQueries, UserQueries, MediaQueries } from '@fnd-platform/dynamodb';
`typescript`
import {
buildUpdateExpression,
buildKeyConditionExpression,
mergeExpressionValues,
} from '@fnd-platform/dynamodb';
`typescript``
import type {
// Entity types
BaseEntity,
EntityDefinition,
EntityType,
EntityInput,
DefinedEntity,
KeyFunctionContext,
KeyConfig,
GSIKeyConfig,
GSIConfig,
// Operation types
GetParams,
PutParams,
UpdateParams,
DeleteParams,
QueryParams,
QueryResult,
BatchKey,
BatchGetParams,
BatchPutRequest,
BatchDeleteRequest,
BatchWriteParams,
// Pre-defined entity types
User,
UserAttributes,
UserRole,
Content,
ContentAttributes,
ContentStatus,
Media,
MediaAttributes,
// Key types
Keys,
UserKeys,
ContentKeys,
MediaKeys,
TagKeys,
GSI1KeyResult,
GSI2KeyResult,
// Query types
ContentListOptions,
UserListOptions,
MediaListOptions,
EntityQueryOptions,
// Expression types
UpdateExpressionResult,
KeyConditionResult,
KeyConditionParams,
// Validation types
ValidationResult,
ValidationError,
} from '@fnd-platform/dynamodb';
- Node.js 20+
- AWS SDK v3 (peer dependency)
- @fnd-platform/api - API handlers using DynamoDB
- @fnd-platform/constructs - DynamoDB table CDK construct
- Single-Table Design Patterns
MIT