"""Utility module to access to DynamoDB.""" import datetime import itertools import os import boto3 from botocore import config as botocore_config DDB_WRITE_MAX_ATTEMPTS = int(os.environ.get('DDB_WRITE_MAX_ATTEMPTS', 10)) def get_dynamodb(max_attempts=None): """Get Boto DynamoDB resource. Args: max_attempts (int): optional max retry attempts Returns: boto3.resources.factory.dynamodb.ServiceResource: DynamoDB resource """ if max_attempts is None: max_attempts = DDB_WRITE_MAX_ATTEMPTS config_instance = botocore_config.Config( retries={'max_attempts': max_attempts}) return boto3.resource('dynamodb', config=config_instance) def get_dynamodb_table(table_name): """Get the DynamoDB table. Args: table_name (str): DynamoDB table name Returns: boto3.resources.factory.dynamodb.Table: DynamoDB table """ dynamodb = get_dynamodb() return dynamodb.Table(table_name) def get_table_count(table_name): """Get the total count of table items. Args: table_name (str): DynamoDB table name Returns: int: table item count """ table = get_dynamodb_table(table_name) resp = full_scan(table, Select='COUNT') return resp.get('Count') def get_ttl_value_for_item(time_delta): """Calculate the TTL value for the item. Args: time_delta (datetime.timedelta): expected time to live Returns: int: TTL in seconds from epoch """ ttl_datetime = datetime.datetime.now() + time_delta return int(ttl_datetime.timestamp()) def get_scan_results(table, scan_kwargs): """Yield scan responses with respect to LastEvaluatedKey. Args: table (boto3.resources.factory.dynamodb.Table): DynamoDB table to scan scan_kwargs (dict): scan key word arguments Returns: dict: individual scan response """ key = True while key: resp = table.scan(**scan_kwargs) key = resp.get('LastEvaluatedKey') if key: scan_kwargs['ExclusiveStartKey'] = key yield resp def full_scan(table, **scan_kwargs): """Do a full table scan, handle the pagination. Args: table (boto3.resources.factory.dynamodb.Table): DynamoDB table to scan scan_kwargs (kwargs): scan key word arguments Returns: dict: combined response similar to original boto3 response """ result = { 'Count': 0, 'ScannedCount': 0} items = [] for resp in get_scan_results(table, scan_kwargs): result['Count'] += resp['Count'] result['ScannedCount'] += resp['ScannedCount'] if 'Items' in resp: items.append(resp['Items']) if items: result['Items'] = list(itertools.chain.from_iterable(items)) return result