def update_record(table_name, item_key: dict, update_dictionary: dict): """ update dynamo DB by dictionary automatically. Don't need to write dynamodb expression as this function will help you write it. Args: dynamodb_resource: a dynamo DB resource instance table_name: the name of the table we want to scan key: the key for update update_dictionary: the dictionary for update Returns: response from dynamo DB """ (update_expression, expression_attr_values) = construct_update_expression( item_key, update_dictionary) table = get_dynamo_table(table_name) response = table.update_item( Key=item_key, UpdateExpression=update_expression, ConditionExpression=Attr('version').eq(update_dictionary['version'] - 1), ExpressionAttributeValues=expression_attr_values, ReturnValues="ALL_NEW") return response
def invalidate_record(table_name: TableNames, item_key: dict, version: int, last_updated_by: str): """ Fake delete a record by setting isValid to false. The caller must have the latest version of the record. This check prevents races, as a part of the optimistic write technique, often also referred to as CAS (compare and swap). """ if table_name is None or item_key is None or version is None or last_updated_by is None: raise ValueError( "Either of these is None: table_name[{}], item_key[{}], version[{}], lastUpdatedBy[{}]" .format(table_name, item_key, version, last_updated_by)) table = get_dynamo_table(table_name) update_expression = 'SET {0} = :{0}, {1} = :{1}, {2} = :{2}'.format( 'isValid', 'version', 'lastUpdatedBy') new_item = { ':isValid': False, ':version': version + 1, ':lastUpdatedBy': last_updated_by } response = table.update_item( Key=item_key, UpdateExpression=update_expression, ConditionExpression=Attr('version').eq(version), ExpressionAttributeValues=new_item, ReturnValues="ALL_NEW") return response
def get_item(table_name, item_key: dict): try: table = get_dynamo_table(table_name) return table.get_item(Key=item_key, ConsistentRead=True)['Item'] except: import traceback import sys traceback.print_tb(sys.exc_info()[2], limit=5) return None
def create_item(event, context): item_unique_id = str(uuid.uuid1()) try: data = event req_data = convert_to_dynamo_compatible(data['body']) user_id = get_user_id_from_gateway_event(event) email = get_email_from_gateway_event(event) username = get_username_from_gateway_event(event) required( req_data['item'], {'description', 'type', 'latitude', 'longitude', 'name', 'city'}) item = { 'id': item_unique_id, 'isValid': True, 'version': 0, 'lastUpdatedBy': user_id, 'lastUpdatedDateTime': now(), 'description': req_data['item']['description'], 'type': req_data['item']['type'], 'latitude': req_data['item']['latitude'], 'longitude': req_data['item']['longitude'], 'username': username, 'userId': user_id } # copy rest of the fields remaining_keys = set(req_data['item'].keys()) - set(item.keys()) for k in remaining_keys: item[k] = req_data['item'][k] table = get_dynamo_table(TableNames.LISTING_TABLE) log.info(get_resolved_dynamo_table_name(TableNames.LISTING_TABLE)) query_response = table.put_item(Item=item) log.info(json.dumps(query_response)) except (KeyError, ClientError) as e: traceback.print_tb(sys.exc_info()[2], limit=5) log.error(sys.exc_info()) raise e(sys.exc_info()) else: response = generate_success_response(item) log.info(response) return response
def query_table_all(table: TableNames, query_params: dict, filter_exp=None): """ A table can be queried for primary index or secondary indexes. For all others use scan_table. query_table is much faster as it uses indexes for query, unlike scan_table which happens to be a full table scan. :param table: :param query_params: :return: """ key_condition = None for k, v in query_params.items(): if key_condition: key_condition = key_condition & Key(k).eq(v) else: key_condition = Key(k).eq(v) response = get_dynamo_table(table).query( KeyConditionExpression=key_condition, FilterExpression=filter_exp) items = response['Items'] return items
def scan_table_all(table_name, filtering_exp=None): """ Perform a scan operation on table. While using this function, if isValid is not set in the filtering_exp, caller receives: VALID as well as INVALID records. DynamoDB table are paginated hence it is not guaranteed that this scan will be able to grab all the data in table. In order to scan the table page by page, we use a loop as indicated bellow. More details can be found here: https://www.tutorialspoint.com/dynamodb/dynamodb_scan.htm Args: dynamodb_resource: a dynamo DB resource instance table_name: the name of the table we want to scan filtering_exp: A valid dynamodb filter expression - Attr('assetStatus').eq('{}'.format('FINAL')) & Attr('isValid').eq(True) Returns: List of Items """ table = get_dynamo_table(table_name) if filtering_exp is not None: response = table.scan(FilterExpression=filtering_exp) else: response = table.scan() # Get items items = response['Items'] while response.get('LastEvaluatedKey'): response = table.scan(ExclusiveStartKey=response['LastEvaluatedKey'], ConsistentRead=True) items += response['Items'] return items