def test_create_projection_expression_invalid_attribute_raises(self): invalid_attributes = [ '', '[0]', 'foo[bar]', 'MyList[-1]', 'MyList[0.4]' ] for attribute in invalid_attributes: with self.assertRaises(ValueError): create_projection_expression([attribute], {})
def test_create_project_expression_with_document_paths(self): attributes_to_get = [Path('foo.bar')[0]] placeholders = {} projection_expression = create_projection_expression( attributes_to_get, placeholders) assert projection_expression == "#0.#1[0]" assert placeholders == {'foo': '#0', 'bar': '#1'}
def test_create_project_expression_with_attribute_names(self): attributes_to_get = [Path('foo.bar', attribute_name=True)[0]] placeholders = {} projection_expression = create_projection_expression( attributes_to_get, placeholders) assert projection_expression == "#0[0]" assert placeholders == {'foo.bar': '#0'}
def test_create_projection_expression_not_a_list(self): attributes_to_get = 'Description' placeholders = {} projection_expression = create_projection_expression( attributes_to_get, placeholders) assert projection_expression == "#0" assert placeholders == {'Description': '#0'}
async def scan(self, table_name, filter_condition=None, attributes_to_get=None, limit=None, return_consumed_capacity=None, exclusive_start_key=None, segment=None, total_segments=None, consistent_read=None, index_name=None): """ Performs the scan operation """ self._check_condition('filter_condition', filter_condition) operation_kwargs = {TABLE_NAME: table_name} name_placeholders = {} expression_attribute_values = {} if filter_condition is not None: filter_expression = filter_condition.serialize( name_placeholders, expression_attribute_values) operation_kwargs[FILTER_EXPRESSION] = filter_expression if attributes_to_get is not None: projection_expression = create_projection_expression( attributes_to_get, name_placeholders) operation_kwargs[PROJECTION_EXPRESSION] = projection_expression if index_name: operation_kwargs[INDEX_NAME] = index_name if limit is not None: operation_kwargs[LIMIT] = limit if return_consumed_capacity: operation_kwargs.update( self.get_consumed_capacity_map(return_consumed_capacity)) if exclusive_start_key: operation_kwargs.update(await self.get_exclusive_start_key_map( table_name, exclusive_start_key)) if segment is not None: operation_kwargs[SEGMENT] = segment if total_segments: operation_kwargs[TOTAL_SEGMENTS] = total_segments if consistent_read: operation_kwargs[CONSISTENT_READ] = consistent_read if name_placeholders: operation_kwargs[EXPRESSION_ATTRIBUTE_NAMES] = self._reverse_dict( name_placeholders) if expression_attribute_values: operation_kwargs[ EXPRESSION_ATTRIBUTE_VALUES] = expression_attribute_values try: return await self.dispatch(SCAN, operation_kwargs) except BOTOCORE_EXCEPTIONS as e: raise ScanError("Failed to scan table: {}".format(e)) from e
def test_create_projection_expression_with_attributes(self): attributes_to_get = [ UnicodeAttribute(attr_name='ProductReviews.FiveStar'), UnicodeAttribute(attr_name='ProductReviews.ThreeStar'), UnicodeAttribute(attr_name='ProductReviews.OneStar') ] placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0, #1, #2" assert placeholders == { 'ProductReviews.FiveStar': '#0', 'ProductReviews.ThreeStar': '#1', 'ProductReviews.OneStar': '#2', }
def test_create_projection_expression(self): attributes_to_get = [ 'Description', 'RelatedItems[0]', 'ProductReviews.FiveStar' ] placeholders = {} projection_expression = create_projection_expression( attributes_to_get, placeholders) assert projection_expression == "#0, #1[0], #2.#3" assert placeholders == { 'Description': '#0', 'RelatedItems': '#1', 'ProductReviews': '#2', 'FiveStar': '#3' }
def test_create_projection_expression_repeated_names(self): attributes_to_get = [ 'ProductReviews.FiveStar', 'ProductReviews.ThreeStar', 'ProductReviews.OneStar' ] placeholders = {} projection_expression = create_projection_expression( attributes_to_get, placeholders) assert projection_expression == "#0.#1, #0.#2, #0.#3" assert placeholders == { 'ProductReviews': '#0', 'FiveStar': '#1', 'ThreeStar': '#2', 'OneStar': '#3' }
def batch_get_item(self, table_name, keys, consistent_read=None, return_consumed_capacity=None, attributes_to_get=None): """ Performs the batch get item operation """ operation_kwargs = { REQUEST_ITEMS: { table_name: {} } } args_map = {} name_placeholders = {} if consistent_read: args_map[CONSISTENT_READ] = consistent_read if return_consumed_capacity: operation_kwargs.update(self.get_consumed_capacity_map(return_consumed_capacity)) if attributes_to_get is not None: projection_expression = create_projection_expression(attributes_to_get, name_placeholders) args_map[PROJECTION_EXPRESSION] = projection_expression if name_placeholders: args_map[EXPRESSION_ATTRIBUTE_NAMES] = self._reverse_dict(name_placeholders) operation_kwargs[REQUEST_ITEMS][table_name].update(args_map) keys_map = {KEYS: []} for key in keys: keys_map[KEYS].append( self.get_item_attribute_map(table_name, key)[ITEM] ) operation_kwargs[REQUEST_ITEMS][table_name].update(keys_map) try: return self.dispatch(BATCH_GET_ITEM, operation_kwargs) except BOTOCORE_EXCEPTIONS as e: raise GetError("Failed to batch get items: {}".format(e), e)
def get_item(self, table_name, hash_key, range_key=None, consistent_read=False, attributes_to_get=None): """ Performs the GetItem operation and returns the result """ operation_kwargs = {} name_placeholders = {} if attributes_to_get is not None: projection_expression = create_projection_expression(attributes_to_get, name_placeholders) operation_kwargs[PROJECTION_EXPRESSION] = projection_expression if name_placeholders: operation_kwargs[EXPRESSION_ATTRIBUTE_NAMES] = self._reverse_dict(name_placeholders) operation_kwargs[CONSISTENT_READ] = consistent_read operation_kwargs[TABLE_NAME] = table_name operation_kwargs.update(self.get_identifier_map(table_name, hash_key, range_key)) try: return self.dispatch(GET_ITEM, operation_kwargs) except BOTOCORE_EXCEPTIONS as e: raise GetError("Failed to get item: {}".format(e), e)
async def get_operation_kwargs(self, table_name, hash_key, range_key=None, key=KEY, attributes=None, attributes_to_get=None, actions=None, condition=None, consistent_read=None, return_values=None, return_consumed_capacity=None, return_item_collection_metrics=None, return_values_on_condition_failure=None): self._check_condition('condition', condition) operation_kwargs = {} name_placeholders = {} expression_attribute_values = {} operation_kwargs[TABLE_NAME] = table_name operation_kwargs.update(await self.get_identifier_map(table_name, hash_key, range_key, key=key)) if attributes and operation_kwargs.get(ITEM) is not None: attrs = await self.get_item_attribute_map(table_name, attributes) operation_kwargs[ITEM].update(attrs[ITEM]) if attributes_to_get is not None: projection_expression = create_projection_expression( attributes_to_get, name_placeholders) operation_kwargs[PROJECTION_EXPRESSION] = projection_expression if condition is not None: condition_expression = condition.serialize( name_placeholders, expression_attribute_values) operation_kwargs[CONDITION_EXPRESSION] = condition_expression if consistent_read is not None: operation_kwargs[CONSISTENT_READ] = consistent_read if return_values is not None: operation_kwargs.update(self.get_return_values_map(return_values)) if return_values_on_condition_failure is not None: operation_kwargs.update( self.get_return_values_on_condition_failure_map( return_values_on_condition_failure)) if return_consumed_capacity is not None: operation_kwargs.update( self.get_consumed_capacity_map(return_consumed_capacity)) if return_item_collection_metrics is not None: operation_kwargs.update( self.get_item_collection_map(return_item_collection_metrics)) if actions is not None: update_expression = Update(*actions) operation_kwargs[UPDATE_EXPRESSION] = update_expression.serialize( name_placeholders, expression_attribute_values) if name_placeholders: operation_kwargs[EXPRESSION_ATTRIBUTE_NAMES] = self._reverse_dict( name_placeholders) if expression_attribute_values: operation_kwargs[ EXPRESSION_ATTRIBUTE_VALUES] = expression_attribute_values return operation_kwargs
def query(self, table_name, hash_key, range_key_condition=None, filter_condition=None, attributes_to_get=None, consistent_read=False, exclusive_start_key=None, index_name=None, limit=None, return_consumed_capacity=None, scan_index_forward=None, select=None): """ Performs the Query operation and returns the result """ self._check_condition('range_key_condition', range_key_condition) self._check_condition('filter_condition', filter_condition) operation_kwargs = {TABLE_NAME: table_name} name_placeholders = {} expression_attribute_values = {} tbl = self.get_meta_table(table_name) if tbl is None: raise TableError("No such table: {}".format(table_name)) if index_name: if not tbl.has_index_name(index_name): raise ValueError("Table {} has no index: {}".format(table_name, index_name)) hash_keyname = tbl.get_index_hash_keyname(index_name) if not hash_keyname: raise ValueError("No hash key attribute for index: {}".format(index_name)) range_keyname = tbl.get_index_range_keyname(index_name) else: hash_keyname = tbl.hash_keyname range_keyname = tbl.range_keyname hash_condition_value = {self.get_attribute_type(table_name, hash_keyname, hash_key): self.parse_attribute(hash_key)} key_condition = getattr(Path([hash_keyname]), '__eq__')(hash_condition_value) if range_key_condition is not None: if range_key_condition.is_valid_range_key_condition(range_keyname): key_condition = key_condition & range_key_condition elif filter_condition is None: # Try to gracefully handle the case where a user passed in a filter as a range key condition (filter_condition, range_key_condition) = (range_key_condition, None) else: raise ValueError("{} is not a valid range key condition".format(range_key_condition)) operation_kwargs[KEY_CONDITION_EXPRESSION] = key_condition.serialize( name_placeholders, expression_attribute_values) if filter_condition is not None: filter_expression = filter_condition.serialize(name_placeholders, expression_attribute_values) # FilterExpression does not allow key attributes. Check for hash and range key name placeholders hash_key_placeholder = name_placeholders.get(hash_keyname) range_key_placeholder = range_keyname and name_placeholders.get(range_keyname) if ( hash_key_placeholder in filter_expression or (range_key_placeholder and range_key_placeholder in filter_expression) ): raise ValueError("'filter_condition' cannot contain key attributes") operation_kwargs[FILTER_EXPRESSION] = filter_expression if attributes_to_get: projection_expression = create_projection_expression(attributes_to_get, name_placeholders) operation_kwargs[PROJECTION_EXPRESSION] = projection_expression if consistent_read: operation_kwargs[CONSISTENT_READ] = True if exclusive_start_key: operation_kwargs.update(self.get_exclusive_start_key_map(table_name, exclusive_start_key)) if index_name: operation_kwargs[INDEX_NAME] = index_name if limit is not None: operation_kwargs[LIMIT] = limit if return_consumed_capacity: operation_kwargs.update(self.get_consumed_capacity_map(return_consumed_capacity)) if select: if select.upper() not in SELECT_VALUES: raise ValueError("{} must be one of {}".format(SELECT, SELECT_VALUES)) operation_kwargs[SELECT] = str(select).upper() if scan_index_forward is not None: operation_kwargs[SCAN_INDEX_FORWARD] = scan_index_forward if name_placeholders: operation_kwargs[EXPRESSION_ATTRIBUTE_NAMES] = self._reverse_dict(name_placeholders) if expression_attribute_values: operation_kwargs[EXPRESSION_ATTRIBUTE_VALUES] = expression_attribute_values try: return self.dispatch(QUERY, operation_kwargs) except BOTOCORE_EXCEPTIONS as e: raise QueryError("Failed to query items: {}".format(e), e)
def test_create_projection_expression(self): attributes_to_get = ['Description', 'RelatedItems[0]', 'ProductReviews.FiveStar'] placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0, #1[0], #2.#3" assert placeholders == {'Description': '#0', 'RelatedItems': '#1', 'ProductReviews': '#2', 'FiveStar': '#3'}
def test_create_projection_expression_repeated_names(self): attributes_to_get = ['ProductReviews.FiveStar', 'ProductReviews.ThreeStar', 'ProductReviews.OneStar'] placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0.#1, #0.#2, #0.#3" assert placeholders == {'ProductReviews': '#0', 'FiveStar': '#1', 'ThreeStar': '#2', 'OneStar': '#3'}
def test_create_projection_expression_invalid_attribute_raises(self): invalid_attributes = ['', '[0]', 'foo[bar]', 'MyList[-1]', 'MyList[0.4]'] for attribute in invalid_attributes: with self.assertRaises(ValueError): create_projection_expression([attribute], {})
def test_create_project_expression_with_document_paths(self): attributes_to_get = [Path('foo.bar')[0]] placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0.#1[0]" assert placeholders == {'foo': '#0', 'bar': '#1'}
def test_create_project_expression_with_attribute_names(self): attributes_to_get = [Path(['foo.bar'])[0]] placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0[0]" assert placeholders == {'foo.bar': '#0'}
def test_create_projection_expression_not_a_list(self): attributes_to_get = 'Description' placeholders = {} projection_expression = create_projection_expression(attributes_to_get, placeholders) assert projection_expression == "#0" assert placeholders == {'Description': '#0'}