/** * Dynamic Key Decorator Examples * * This file demonstrates the @UseRedisLockWithDynamicKey decorator which * supports dynamic key generation from function parameters using template syntax. * * Template Syntax: * - {0}, {1} - Positional parameter access * - {userId} - Named parameter access (requires emitDecoratorMetadata) * - {user.id} - Nested property access * - {items.0.name} - Array index access */ import { RedisLockService } from '../index'; interface UserDto { id: string; name: string; email: string; profile?: { id: string; bio: string; }; } interface PostDto { userId: string; postId: string; title: string; content: string; } interface PaymentDto { paymentId: string; amount: number; currency: string; } /** * Example 1: Using positional parameter access {0}, {1}, etc. * This works without requiring any special TypeScript configuration. */ export declare class PositionalAccessExample { private readonly lockService; private readonly logger; constructor(lockService: RedisLockService); /** * Single parameter - locks per user * Lock key format: lock:user:{userId} */ updateUserById(userId: string, data: Partial): Promise; /** * Multiple parameters - creates composite key * Lock key format: lock:user:{userId}:post:{postId} */ updatePostById(userId: string, postId: string, data: Partial): Promise; /** * Static prefix with dynamic suffix * Lock key format: lock:payment:process:{0} */ processPayment(paymentId: string): Promise; private saveUser; private savePost; private chargePayment; } /** * Example 2: Accessing nested properties from parameter objects * Uses dot notation to navigate object structure */ export declare class NestedPropertyAccessExample { private readonly logger; /** * Single nested property - {user.id} * Lock key format: lock:user:{user.id}:profile */ updateProfile(user: UserDto): Promise; /** * Multiple nested properties from single parameter * Lock key format: lock:{from.userId}:chat:{to.userId} */ sendMessage(from: UserDto, to: UserDto, message: string): Promise; /** * Deep nesting with object navigation * Lock key format: lock:order:{order.customer.id}:{order.items.0.id} */ processFirstItem(order: { customer: { id: string; }; items: Array<{ id: string; }>; }): Promise; private saveProfile; private deliverMessage; private processItem; } /** * Example 3: Accessing array elements by index * Uses numeric path segments to access array items */ export declare class ArrayIndexAccessExample { private readonly logger; /** * Access first item in array * Lock key format: lock:process:{items.0.id} */ processFirstItem(items: Array<{ id: string; }>): Promise; /** * Access multiple array indices * Lock key format: lock:batch:{items.0.id}:{items.1.id} */ processBatch(items: Array<{ id: string; }>): Promise; /** * Nested array access * Lock key format: lock:group:{groups.0.members.0.userId} */ processFirstGroupMember(groups: Array<{ members: Array<{ userId: string; }>; }>): Promise; private processItem; private processTwoItems; private processMember; } /** * Example 4: Different error handling strategies for missing parameters */ export declare class ErrorHandlingExample { private readonly logger; /** * Default behavior: SKIP execution when parameter is missing * Lock key format: lock:user:{userId}:data */ processWithDefaultSkip(userId?: string): Promise; /** * Use FALLBACK key when parameter is missing * Lock key format: lock:shared-user-lock (fallback) */ processWithFallback(userId?: string): Promise; /** * THROW error when parameter is missing * Lock key format: lock:user:{userId}:critical */ processWithError(userId: string): Promise; private processData; } /** * Example 5: Using the Smart decorator variant with automatic fallback * Fallback key is auto-generated as ClassName:methodName */ export declare class SmartDecoratorExample { private readonly logger; /** * Uses {userId} template with automatic fallback to SmartDecoratorExample:updateUserData */ updateUserData(userId: string, data: any): Promise; /** * Multiple parameters with smart fallback * Falls back to SmartDecoratorExample:syncData if parameters are missing */ syncData(userId: string, dataType: string): Promise; private saveUserData; private performSync; } /** * Example 6: Using dynamic keys in scheduled tasks * Prevents overlapping executions for the same resource */ export declare class ScheduledTaskExample { private readonly logger; /** * Scheduled task that processes items dynamically * Each item gets its own lock, allowing parallel processing of different items */ cleanupTenantData(tenantId: string): Promise; /** * Data synchronization with per-user locks */ syncUserData(userId: string, dataSource: string): Promise; /** * Report generation with WAIT strategy * Ensures reports for the same entity are generated sequentially */ generateReport(entityType: string, entityId: string): Promise; private performCleanup; private syncFromSource; private createReport; } /** * Example 7: Practical real-world scenarios */ export declare class RealWorldExample { private readonly logger; /** * Prevent double-spending in payment processing * Locks by payment ID to ensure each payment is processed exactly once */ processPayment(payment: PaymentDto): Promise; /** * Rate limiting per user * Locks by user ID to prevent rapid successive requests */ performRateLimitedAction(userId: string, action: string): Promise; /** * Inventory management with item-level locks * Allows concurrent updates to different items */ updateInventory(warehouseId: string, itemId: string, quantityDelta: number): Promise; /** * Cache invalidation with granular locks */ invalidateCache(cacheKey: string): Promise; /** * User profile update with optimistic locking behavior */ updateUserProfile(userId: string, profileData: Partial): Promise; private chargeAccount; private recordPayment; private executeAction; private adjustInventory; private clearCache; private saveProfile; } export {}; /** * TIPS FOR USING DYNAMIC KEY DECORATORS: * * 1. Use positional access {0}, {1} for maximum compatibility * - Works without any special TypeScript configuration * - Most reliable across different build setups * * 2. Keep lock keys simple and predictable * - Avoid deeply nested paths when possible * - Use consistent patterns across your application * * 3. Choose appropriate error handling: * - SKIP (default): For non-critical operations * - FALLBACK: When you want a default behavior * - ERROR: For critical operations that require valid parameters * * 4. Use appropriate lock strategies: * - SKIP: For idempotent operations or scheduled tasks * - WAIT: For operations that must complete sequentially * - THROW: For critical operations that need exclusive access * * 5. Set appropriate TTL values: * - Too short: Lock may expire during operation * - Too long: Resources stay locked longer than necessary * - Consider typical operation duration + safety margin * * 6. Avoid overly specific keys for high-contention scenarios: * - More specific keys = more parallelism = more potential conflicts * - Balance between granularity and contention */