UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

383 lines 13.2 kB
import type { OperationType, AmplifyModelType, CacheConfig, QueryFactoryResult, SortDirection, AmplifyAuthMode } from './types'; import type { QueryCache } from './cache'; /** * Extracts identifier fields from input data using schema metadata. * * Handles both single and composite primary keys by extracting the appropriate * identifier fields from the input based on the entity's schema definition. * * @param input - The input data object containing potential identifier fields * @param entityName - Name of the entity to extract identifiers for * @returns Object containing only the identifier fields and their values * * @example * ```typescript * // Single key * const id = extractIdentifier({ userId: "123", name: "John" }, "User"); * // Returns: { userId: "123" } * * // Composite key * const compositeId = extractIdentifier( * { tenantId: "org1", userId: "123", name: "John" }, * "UserProfile" * ); * // Returns: { tenantId: "org1", userId: "123" } * ``` */ export declare const extractIdentifier: (input: Record<string, unknown>, entityName: string) => Record<string, unknown>; /** * Logs the successful completion of a database operation. * * Creates standardized log entries for successful database operations, * including operation type and optional additional context information. * * @internal * @param operation - The type of database operation that completed * @param additionalInfo - Optional additional information to include in the log * * @example * ```typescript * logSuccess("create", { nameStr: "User", id: "123" }); * // Logs: "Successfully created" with additional context * ``` */ export declare const logSuccess: (operation: OperationType, additionalInfo?: unknown) => void; /** * Validates GraphQL-like response objects for correctness and data presence. * * Performs comprehensive validation of database responses including: * - Response object existence and structure * - GraphQL error detection and reporting * - Data presence validation * - Structured error logging with context * * @template R - The expected type of the data property in the response * @param props - Validation configuration object * @param props.response - The response object to validate * @param props.operation - The operation that generated this response * @param props.name - The model name for context * @param props.input - Optional input data for error context * @returns The validated data from the response * @throws {Error} When response is invalid, malformed, or contains errors * * @example * ```typescript * const userData = validateResponse({ * response: { data: { id: "123", name: "John" }, errors: [] }, * operation: "get", * name: "User", * input: { userId: "123" } * }); * // Returns: { id: "123", name: "John" } * ``` */ export declare const validateResponse: <R>(props: { response: { data: R | null; errors?: unknown[]; } | null | undefined; operation: string; name: string; input?: unknown; }) => R; /** * Convenience wrapper functions that delegate to ClientManager methods. * * These provide a simpler API for common use cases while maintaining * backwards compatibility with the previous function-based interface. */ /** * Retrieves query factories with automatic initialization of missing entities. * * Convenience wrapper around ClientManager.getInstance().getQueryFactories() * that automatically creates query factories for entities that haven't been * initialized yet. * * @template TTypes - Record of all available Amplify model types * @template TSelected - Selected entity names as string literals * @param config - Configuration for query factory retrieval * @param config.entities - Array of entity names to retrieve factories for * @param config.cache - Optional cache configuration for all factories * @param config.clientKey - Optional client key for isolation (default: "default") * @returns Promise resolving to object with query factories for each entity * * @example * ```typescript * const queries = await getQueryFactories({ * entities: ["User", "Post", "Comment"], * cache: { enabled: true, maxSize: 50 * 1024 * 1024 }, * clientKey: "main" * }); * * const user = await queries.User.get({ input: { userId: "123" } }); * ``` */ export declare function getQueryFactories<TTypes extends Record<string, AmplifyModelType>, TSelected extends keyof TTypes & string>(config: { entities: readonly TSelected[]; cache?: CacheConfig; clientKey?: string; }): Promise<{ [K in TSelected]: QueryFactoryResult<K, TTypes>; }>; /** * Safely extracts error messages from unknown error objects. * * Handles various error types including Error instances, strings, and other objects * by attempting to extract a meaningful error message. * * @param error - Unknown error object to extract message from * @returns String representation of the error message * * @example * ```typescript * try { * await someOperation(); * } catch (error) { * const message = getErrorMessage(error); * console.log(`Operation failed: ${message}`); * } * ``` */ export declare function getErrorMessage(error: unknown): string; /** * Determines if an error message indicates a "not found" condition. * * Specifically checks for the error message generated by our validateResponse() * function when no data is returned from a database operation. * * @param message - Error message to analyze * @returns True if the message indicates no data was returned * * @example * ```typescript * // Error from validateResponse when data is null/undefined * const errorMsg = "No data returned for User get"; * if (isNotFoundError(errorMsg)) { * // Handle as 404 Not Found * return RestErrors.notFound("User not found"); * } * ``` */ export declare function isNotFoundError(message: string): boolean; /** * Determines if an error message indicates a validation failure. * * Checks error messages against patterns that AWS AppSync returns for validation errors, * including schema type mismatches, constraint violations, and invalid scalar types. * * @param message - Error message to analyze * @returns True if the message indicates a validation error * * @example * ```typescript * // AppSync schema validation error * const errorMsg = "Validation error of type WrongType: argument 'email' with value 'StringValue{value='not-a-valid-email'}' is not a valid 'AWSEmail'"; * if (isValidationError(errorMsg)) { * // Handle as 400 Bad Request * return RestErrors.validation("Invalid input data"); * } * * // AppSync type mismatch error * const typeError = "Variable '$input' of type 'CreateUserInput' used in position expecting type 'CreateUserInput!'"; * if (isValidationError(typeError)) { * return RestErrors.validation("Required field missing"); * } * ``` */ export declare function isValidationError(message: string): boolean; /** * Determines if an error message indicates a data conflict. * * Checks error messages against patterns that AWS AppSync and DynamoDB return for * conflict situations, including conditional check failures, version mismatches, * and optimistic concurrency control violations. * * @param message - Error message to analyze * @returns True if the message indicates a conflict error * * @example * ```typescript * // DynamoDB conditional check failure * const conditionalError = "The conditional request failed"; * if (isConflictError(conditionalError)) { * // Handle as 409 Conflict * return RestErrors.conflict("Item already exists or has been modified"); * } * * // AppSync version conflict * const versionError = "ConflictUnhandled: Conflict resolver rejects mutation."; * if (isConflictError(versionError)) { * return RestErrors.conflict("Data was modified by another user"); * } * ``` */ export declare function isConflictError(message: string): boolean; /** * Creates deterministic hash strings from objects using schema-aware identifier fields. * * Generates consistent cache keys by extracting identifier fields from the schema * and creating SHA-256 hashes. Falls back to JSON serialization if identifier * extraction fails. * * @param obj - Object to generate hash from * @param entityName - Name of the entity for identifier field extraction * @returns SHA-256 hash string for use as cache key * * @example * ```typescript * const user = { userId: "123", email: "user@example.com", name: "John" }; * const hash = createObjectHash(user, "User"); * // Returns hash of { userId: "123" } (only identifier fields) * * const cacheKey = `User:get:${hash}`; * ``` */ export declare function createObjectHash(obj: Record<string, unknown>, entityName: string): string; /** * Builds parameters object for list operations. * * @param params - Configuration for list parameters * @returns Object containing only the defined parameters * * @example * ```typescript * const params = buildListParams({ * filter: { status: { eq: 'active' } }, * limit: 50, * sortDirection: 'desc' * }); * // Returns: { filter: {...}, limit: 50, sortDirection: 'desc' } * ``` */ export declare function buildListParams(params: { filter?: unknown | undefined; sortDirection?: SortDirection | undefined; limit?: number | undefined; authMode?: AmplifyAuthMode | undefined; selectionSet?: readonly string[] | undefined; }): Record<string, unknown>; /** * Builds parameters for index query operations. * * @param input - Base input object for the query * @param params - Additional parameters to merge * @returns Combined parameter object * * @example * ```typescript * const params = buildIndexParams( * { userId: "123" }, * { limit: 20, filter: { active: { eq: true } } } * ); * // Returns: { userId: "123", limit: 20, filter: {...} } * ``` */ export declare function buildIndexParams(input: Record<string, unknown>, params: { filter?: unknown | undefined; limit?: number | undefined; authMode?: AmplifyAuthMode | undefined; selectionSet?: readonly string[] | undefined; nextToken?: string | undefined; }): Record<string, unknown>; /** * Generic cache check for query operations. * * Checks the cache for a previously stored query result based on * the operation type and hash of query parameters. * * @template T - Type of the cached result * @param config - Cache check configuration * @returns Cached result if available, null otherwise * * @example * ```typescript * const cached = checkQueryCache<PaginationResult<User>>({ * nameStr: "User", * cacheType: "list", * isCacheable: true, * hashData: { limit: 50 }, * cache: queryCache * }); * ``` */ export declare function checkQueryCache<T>(config: { nameStr: string; cacheType: 'list' | 'index'; isCacheable: boolean; hashData: Record<string, unknown>; cache?: QueryCache | undefined; }): T | null; /** * Generic cache set for query operations. * * Stores a query result in the cache if caching is eligible based * on the operation type and parameters. * * @template T - Type of the result to cache * @param config - Cache set configuration * * @example * ```typescript * setQueryCache({ * nameStr: "User", * cacheType: "list", * isCacheable: true, * hashData: { limit: 50 }, * result: { items: [...], scannedCount: 50 }, * cache: queryCache * }); * ``` */ export declare function setQueryCache<T>(config: { nameStr: string; cacheType: 'list' | 'index'; isCacheable: boolean; hashData: Record<string, unknown>; result: T; cache?: QueryCache | undefined; }): void; /** * Handles pagination consistently across database operations. * * Provides automatic pagination following with safety limits and comprehensive * error handling. Can retrieve all pages automatically or handle single-page * operations with consistent response formatting. * * @template T - Type of items being paginated * @param operation - Function that performs the paginated operation * @param params - Parameters to pass to the operation function * @param options - Pagination behavior configuration * @param options.followNextToken - Whether to automatically follow all pages * @param options.maxPages - Safety limit to prevent infinite loops (default: 10) * @returns Promise resolving to aggregated pagination results * * @example * ```typescript * // Single page * const singlePage = await handlePagination( * (params) => model.list(params), * { limit: 20 }, * { followNextToken: false } * ); * * // All pages * const allPages = await handlePagination( * (params) => model.list(params), * { limit: 100 }, * { followNextToken: true, maxPages: 50 } * ); * ``` */ export declare function handlePagination<T>(operation: (params?: Record<string, unknown>) => Promise<{ data: T[]; errors?: unknown[]; nextToken?: string; }>, params?: Record<string, unknown>, options?: { followNextToken?: boolean; maxPages?: number; }): Promise<{ items: T[]; nextToken?: string; scannedCount?: number; }>; //# sourceMappingURL=helpers.d.ts.map