Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 278 additions & 0 deletions .kiro/specs/operation-samples-showcase/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
# Design Document: Operation Samples Showcase

## Overview

This project provides a standalone .NET 8 class library containing compilable code samples that demonstrate FluentDynamoDb API usage compared to the raw AWS SDK for DynamoDB. The samples are designed for screenshots and video presentations, showing the verbosity reduction and API improvements offered by FluentDynamoDb.

The project uses a simple Order/OrderLine domain with a single-table design pattern. Each DynamoDB operation type has a dedicated sample file containing four methods demonstrating different coding styles:
1. Raw AWS SDK with explicit AttributeValue dictionaries
2. FluentDynamoDb manual builder with WithAttribute()/WithValue()
3. FluentDynamoDb formatted string with {0}, {1} placeholders
4. FluentDynamoDb lambda expressions with entity accessors

## Architecture

```
examples/
└── OperationSamples/
├── OperationSamples.csproj
├── Models/
│ ├── Order.cs
│ ├── OrderLine.cs
│ └── OrdersTable.cs
└── Samples/
├── GetSamples.cs
├── PutSamples.cs
├── UpdateSamples.cs
├── DeleteSamples.cs
├── QuerySamples.cs
├── ScanSamples.cs
├── TransactionGetSamples.cs
├── TransactionWriteSamples.cs
├── BatchGetSamples.cs
└── BatchWriteSamples.cs
```

The project is located under the `examples/` folder alongside other example projects (InvoiceManager, StoreLocator, TodoList, TransactionDemo).

### DynamoDB Table Schema

Single-table design with the following key structure:
- **Table Name**: `Orders`
- **Partition Key (pk)**: `ORDER#{OrderId}`
- **Sort Key (sk)**:
- `META` for Order metadata
- `LINE#{LineId}` for OrderLine items

### Sample Method Naming Convention

Each sample file contains a static class with four methods following this pattern:
- `RawSdk{Operation}Async` - Direct AWS SDK usage
- `FluentManual{Operation}Async` - FluentDynamoDb with manual expressions
- `FluentFormatted{Operation}Async` - FluentDynamoDb with format strings
- `FluentLambda{Operation}Async` - FluentDynamoDb with lambda expressions

## Components and Interfaces

### Models

#### Order Entity
```csharp
[DynamoDbEntity]
public partial class Order : IDynamoDbEntity
{
[PartitionKey]
public string Pk { get; set; } // "ORDER#{OrderId}"

[SortKey]
public string Sk { get; set; } // "META"

public string OrderId { get; set; }
public string CustomerId { get; set; }
public DateTime OrderDate { get; set; }
public string Status { get; set; } // "Pending", "Shipped", "Delivered"
public decimal TotalAmount { get; set; }
}
```

#### OrderLine Entity
```csharp
[DynamoDbEntity]
public partial class OrderLine : IDynamoDbEntity
{
[PartitionKey]
public string Pk { get; set; } // "ORDER#{OrderId}"

[SortKey]
public string Sk { get; set; } // "LINE#{LineId}"

public string LineId { get; set; }
public string ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
}
```

#### OrdersTable
```csharp
public partial class OrdersTable : DynamoDbTableBase
{
public OrdersTable(IAmazonDynamoDB client) : base(client, "Orders") { }

// Generated entity accessors:
// public OrderAccessor Orders { get; }
// public OrderLineAccessor OrderLines { get; }
}
```

#### OrderUpdateModel (for lambda expression updates)
```csharp
/// <summary>
/// Update model for Order entity used with lambda expression Set() operations.
/// </summary>
public class OrderUpdateModel
{
[DynamoDbAttribute("orderStatus")]
public string? Status { get; set; }

[DynamoDbAttribute("modifiedAt")]
public DateTime? ModifiedAt { get; set; }

[DynamoDbAttribute("totalAmount")]
public decimal? TotalAmount { get; set; }
}
```

### Sample File Structure

Each sample file follows this structure:
```csharp
namespace FluentDynamoDb.OperationSamples.Samples;

public static class {Operation}Samples
{
// Returns AWS SDK response, then converts to domain model for equivalency
public static async Task<TEntity> RawSdk{Operation}Async(IAmazonDynamoDB client, ...) { }
public static async Task<TEntity> FluentManual{Operation}Async(OrdersTable table, ...) { }
public static async Task<TEntity> FluentFormatted{Operation}Async(OrdersTable table, ...) { }
public static async Task<TEntity> FluentLambda{Operation}Async(OrdersTable table, ...) { }
}
```

### Lambda Expression Patterns

FluentLambda methods should demonstrate the full power of lambda expressions:

#### Update Operations
```csharp
// Use Set(x => new UpdateModel { ... }) syntax
await table.Orders.Update(pk, sk)
.Set(x => new OrderUpdateModel
{
Status = newStatus,
ModifiedAt = modifiedAt
})
.UpdateAsync();
```

#### Condition Expressions
```csharp
// Use AttributeExists/AttributeNotExists via lambda
await table.Orders.Put(order)
.Where(x => x.Pk.AttributeNotExists())
.PutAsync();

await table.Orders.Update(pk, sk)
.Where(x => x.Pk.AttributeExists())
.Set(x => new OrderUpdateModel { Status = newStatus })
.UpdateAsync();
```

#### Express-Route Methods
```csharp
// Use express-route methods instead of builder chains
await table.Orders.PutAsync(order); // NOT: Put(order).PutAsync()
var order = await table.Orders.GetAsync(pk, sk); // NOT: Get(pk, sk).GetItemAsync()
await table.Orders.DeleteAsync(pk, sk); // NOT: Delete(pk, sk).DeleteAsync()
```

### Response Handling Pattern

Raw SDK methods should demonstrate full equivalency by converting responses to domain models:

```csharp
public static async Task<Order?> RawSdkGetAsync(IAmazonDynamoDB client, string orderId)
{
var response = await client.GetItemAsync(request);

if (response.Item == null || response.Item.Count == 0)
return null;

// Manual conversion to show equivalency
return new Order
{
Pk = response.Item["pk"].S,
Sk = response.Item["sk"].S,
OrderId = response.Item["orderId"].S,
// ... other properties
};
}
```

## Data Models

### Key Patterns

| Entity | Partition Key | Sort Key |
|--------|--------------|----------|
| Order | `ORDER#{OrderId}` | `META` |
| OrderLine | `ORDER#{OrderId}` | `LINE#{LineId}` |

### Sample Data Values

For consistency across samples:
- OrderId: `"ORD-001"`, `"ORD-002"`
- LineId: `"LN-001"`, `"LN-002"`
- CustomerId: `"CUST-123"`
- Status values: `"Pending"`, `"Shipped"`, `"Delivered"`

## Correctness Properties

*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*

Based on the prework analysis, most requirements for this showcase project are structural/stylistic and not amenable to property-based testing. The primary testable property is:

### Property 1: Sample File Method Structure
*For any* sample file in the Samples folder, the file SHALL contain exactly four public static async Task methods with names matching the patterns: `RawSdk*Async`, `FluentManual*Async`, `FluentFormatted*Async`, and `FluentLambda*Async`.

**Validates: Requirements 1.1**

### Verification Examples (Not Properties)

The following requirements are verified through specific examples rather than universal properties:

- **Build Verification**: Running `dotnet build` produces exit code 0 (Requirements 3.1)
- **Project Configuration**: The csproj contains `<TargetFramework>net8.0</TargetFramework>` and `<Nullable>enable</Nullable>` (Requirements 3.2, 3.3)
- **Model Files Exist**: `Order.cs` and `OrderLine.cs` exist in Models folder (Requirements 4.1)
- **Namespace Consistency**: All files use `FluentDynamoDb.OperationSamples` namespace (Requirements 4.4)
- **Sample Files Exist**: All 10 sample files exist (Requirements 5.1-5.10)

## Error Handling

Since this is a showcase project that doesn't execute against real AWS resources, error handling is minimal:

- Methods may throw `NotImplementedException` only if absolutely necessary for compilation (avoided per requirements)
- No try-catch blocks needed as code is for demonstration only
- AWS SDK exceptions are not handled as the code won't execute

## Testing Strategy

### Dual Testing Approach

Given the nature of this showcase project (compilable but non-executable code), testing focuses on:

#### Unit Tests
- Verify project compiles successfully with `dotnet build`
- Verify all expected files exist in the correct locations
- Verify namespace consistency across all files

#### Property-Based Tests

**Property-Based Testing Library**: FsCheck with xUnit integration

**Property 1 Implementation**: Sample File Method Structure
```csharp
// Feature: operation-samples-showcase, Property 1: Sample File Method Structure
// Validates: Requirements 1.1
[Property]
public Property AllSampleFilesHaveFourMethods()
{
// For each sample file, verify it contains exactly 4 methods
// with the correct naming patterns
}
```

### Test Configuration
- Property tests run minimum 100 iterations
- Tests tagged with feature and property references per design requirements
116 changes: 116 additions & 0 deletions .kiro/specs/operation-samples-showcase/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Requirements Document

## Introduction

This document specifies requirements for a standalone .NET 8 example project that demonstrates FluentDynamoDb API usage compared to the raw AWS SDK for DynamoDB. The project's sole purpose is to provide clean, compilable code samples suitable for screenshots and video presentations. The code must compile but does not need to execute against real AWS resources.

## Glossary

- **FluentDynamoDb**: The Oproto.FluentDynamoDb library providing fluent-style API wrappers for DynamoDB operations
- **Raw SDK**: Direct usage of AWSSDK.DynamoDBv2 without any abstraction layers
- **Manual Builder**: FluentDynamoDb style using explicit expression strings with WithAttribute() and WithValue() methods
- **Formatted String**: FluentDynamoDb style using C# string interpolation with positional placeholders like {0}, {1}
- **Lambda Mode**: FluentDynamoDb style using strongly-typed lambda expressions and entity accessors
- **Entity Accessor**: Generated type-safe property on a table class providing direct access to entity operations (e.g., table.Orders)
- **Operation Sample**: A set of four methods demonstrating the same DynamoDB operation in different coding styles

## Requirements

### Requirement 1

**User Story:** As a developer evaluating FluentDynamoDb, I want to see side-by-side code comparisons for each DynamoDB operation type, so that I can understand the verbosity reduction and API improvements.

#### Acceptance Criteria

1. WHEN a sample file is created for an operation type THEN the System SHALL include exactly four public static async methods: RawSdk, FluentManual, FluentFormatted, and FluentLambda variants
2. WHEN the Raw SDK method is implemented THEN the System SHALL use only AWSSDK.DynamoDBv2 types with explicit AttributeValue dictionaries and string-based expressions
3. WHEN the FluentManual method is implemented THEN the System SHALL use FluentDynamoDb builders with WithAttribute() and WithValue() method calls
4. WHEN the FluentFormatted method is implemented THEN the System SHALL use FluentDynamoDb builders with positional placeholder strings like {0}, {1}
5. WHEN the FluentLambda method is implemented THEN the System SHALL use strongly-typed lambda expressions with entity accessor properties, including Set(x => new UpdateModel { ... }) for updates and Where(x => x.Property.AttributeNotExists()) for conditions

### Requirement 2

**User Story:** As a presenter creating screenshots, I want each sample method to be concise and focused, so that the code fits well in presentation slides.

#### Acceptance Criteria

1. WHEN a standard operation sample method is written THEN the System SHALL contain between 5 and 20 lines of code
2. WHEN a transaction or batch operation sample is written THEN the System SHALL show the full verbose Raw SDK implementation without helper methods to maximize the contrast
3. WHEN sample methods are written THEN the System SHALL avoid TODO comments and placeholder implementations
4. WHEN sample methods are written THEN the System SHALL use minimal inline comments only where they clarify approach differences

### Requirement 8

**User Story:** As a developer comparing approaches, I want the Raw SDK methods to return actual AWS SDK responses and the Fluent methods to return equivalent domain models, so that I can see full equivalency between approaches.

#### Acceptance Criteria

1. WHEN a Raw SDK method returns a response THEN the System SHALL include manual conversion of the response back to the domain model to demonstrate full equivalency
2. WHEN a Fluent method returns a result THEN the System SHALL return the same domain model type as the converted Raw SDK response

### Requirement 9

**User Story:** As a developer learning FluentDynamoDb, I want the lambda expression samples to demonstrate the full power of lambda expressions including AttributeExists and AttributeNotExists conditions, so that I understand the type-safe condition capabilities.

#### Acceptance Criteria

1. WHEN a FluentLambda Update method is implemented THEN the System SHALL use Set(x => new UpdateModel { ... }) syntax with lambda expressions
2. WHEN a FluentLambda method includes a condition THEN the System SHALL use Where(x => x.Property.AttributeExists()) or Where(x => x.Property.AttributeNotExists()) syntax where appropriate
3. WHEN a FluentLambda method uses entity accessors THEN the System SHALL use express-route methods like PutAsync(entity), GetAsync(key), and DeleteAsync(key) instead of builder chains like Put(entity).PutAsync()

### Requirement 3

**User Story:** As a developer, I want the sample project to compile successfully, so that I can verify the code examples are syntactically correct.

#### Acceptance Criteria

1. WHEN the project is built with `dotnet build` THEN the System SHALL compile without errors
2. WHEN the project references FluentDynamoDb THEN the System SHALL use the local project reference from the solution
3. WHEN the project is structured THEN the System SHALL target .NET 8.0 and use nullable reference types

### Requirement 4

**User Story:** As a documentation maintainer, I want a consistent domain model across all samples, so that viewers can follow the examples without confusion.

#### Acceptance Criteria

1. WHEN domain models are defined THEN the System SHALL include Order and OrderLine entities at minimum
2. WHEN the DynamoDB table schema is represented THEN the System SHALL use a single-table design with pk="ORDER#{OrderId}" and sk="META" or "LINE#{LineId}"
3. WHEN entity properties are defined THEN the System SHALL include realistic fields without excessive complexity
4. WHEN the namespace is defined THEN the System SHALL use FluentDynamoDb.OperationSamples consistently

### Requirement 5

**User Story:** As a developer reviewing samples, I want all ten DynamoDB operation types covered, so that I have comprehensive reference material.

#### Acceptance Criteria

1. WHEN sample files are created THEN the System SHALL include GetSamples.cs for GetItem operations
2. WHEN sample files are created THEN the System SHALL include PutSamples.cs for PutItem operations
3. WHEN sample files are created THEN the System SHALL include UpdateSamples.cs for UpdateItem operations
4. WHEN sample files are created THEN the System SHALL include DeleteSamples.cs for DeleteItem operations
5. WHEN sample files are created THEN the System SHALL include QuerySamples.cs for Query operations
6. WHEN sample files are created THEN the System SHALL include ScanSamples.cs for Scan operations
7. WHEN sample files are created THEN the System SHALL include TransactionGetSamples.cs for TransactGetItems operations
8. WHEN sample files are created THEN the System SHALL include TransactionWriteSamples.cs for TransactWriteItems operations
9. WHEN sample files are created THEN the System SHALL include BatchGetSamples.cs for BatchGetItem operations
10. WHEN sample files are created THEN the System SHALL include BatchWriteSamples.cs for BatchWriteItem operations

### Requirement 6

**User Story:** As a presenter, I want the formatted string examples to demonstrate date formatting capabilities, so that viewers understand the full power of the format string approach.

#### Acceptance Criteria

1. WHEN a formatted string sample involves date values THEN the System SHALL demonstrate the {0:o} ISO 8601 format specifier where appropriate
2. WHEN formatted string samples are written THEN the System SHALL show how placeholders eliminate manual ExpressionAttributeValues management

### Requirement 7

**User Story:** As a developer, I want transaction and batch samples to show multi-entity operations, so that I understand how FluentDynamoDb handles complex scenarios.

#### Acceptance Criteria

1. WHEN transaction write samples are implemented THEN the System SHALL demonstrate operations across multiple entity types in a single transaction
2. WHEN batch operation samples are implemented THEN the System SHALL demonstrate processing multiple items of different types
3. WHEN the Raw SDK transaction/batch samples are written THEN the System SHALL avoid helper methods to show the full verbosity contrast
Loading
Loading