@energica-city/shared-amplify-utils
Version:
Shared utilities for AWS Amplify projects
383 lines • 13.2 kB
TypeScript
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