Example #1
0
    def test_put_tasks_updates_with_optimistic_lock(self):
        # GIVEN
        table_client = mock.Mock()
        table_client.query = mock.Mock(
            return_value={'Items': [dict(DDB_RECORD_ENCODED)]})

        key = DdbRecordKey(cluster_arn='FOO',
                           service_name='test.myexample.com')
        records_table = RecordsTableAccessor(table_client=table_client)

        running = [
            TaskInfo(task_arn='TASK1_ARN',
                     enis=[
                         EniInfo(eni_id='TASK1_ENI1_ID',
                                 public_ipv4='1.1.1.1'),
                     ])
        ]

        # WHEN
        records_table.put_update_optimistically(
            key=key, update=RecordUpdate(running_tasks=running))

        # THEN
        condition_expression = table_client.put_item.call_args.kwargs[
            'ConditionExpression']
        expr, atts, vals = ConditionExpressionBuilder().build_expression(
            condition_expression)
        self.assertEqual(vals, {':v0': 12})
Example #2
0
    def test_put_tasks_creates_with_optimistic_lock(self):
        # GIVEN
        table_client = mock.Mock()
        table_client.query = mock.Mock(return_value={'Items': []})

        key = DdbRecordKey(cluster_arn='a', service_name='b')
        records_table = RecordsTableAccessor(table_client=table_client)

        running = [
            TaskInfo(task_arn='TASK1_ARN',
                     enis=[
                         EniInfo(eni_id='TASK1_ENI1_ID',
                                 public_ipv4='1.1.1.1'),
                     ])
        ]

        # WHEN
        records_table.put_update_optimistically(
            key=key, update=RecordUpdate(running_tasks=running))

        # THEN
        table_client.put_item.assert_called()
        item = table_client.put_item.call_args.kwargs['Item']
        self.assertEqual(item['version'], 1)

        condition_expression = table_client.put_item.call_args.kwargs[
            'ConditionExpression']
        expr, atts, vals = ConditionExpressionBuilder().build_expression(
            condition_expression)
        self.assertEqual(expr, '(attribute_not_exists(#n0) OR #n1 = :v0)')
        self.assertEqual(atts, {'#n0': 'version', '#n1': 'version'})
        self.assertEqual(vals, {':v0': 0})
Example #3
0
    def __init__(self, transformer=None, condition_builder=None,
                 serializer=None, deserializer=None):
        self._transformer = transformer
        if transformer is None:
            self._transformer = ParameterTransformer()

        self._condition_builder = condition_builder
        if condition_builder is None:
            self._condition_builder = ConditionExpressionBuilder()

        self._serializer = serializer
        if serializer is None:
            self._serializer = TypeSerializer()

        self._deserializer = deserializer
        if deserializer is None:
            self._deserializer = TypeDeserializer()
Example #4
0
 def _stringify_conditions(self, request_data):
     """
     convert Key and Attr object of DynamoDB to strings.
     :param request_data: DynamoDB request data
     :return: updated request data
     """
     for field in self.CONDITION_FIELDS:
         if field in request_data:
             try:
                 request_data[field] = str(
                     ConditionExpressionBuilder().build_expression(
                         request_data[field],
                         field == 'KeyConditionExpression'))
             except Exception:  # pylint: disable=W0703
                 pass
     return request_data
Example #5
0
    def __init__(self, transformer=None, condition_builder=None, serializer=None, deserializer=None):
        self._transformer = transformer
        if transformer is None:
            self._transformer = ParameterTransformer()

        self._condition_builder = condition_builder
        if condition_builder is None:
            self._condition_builder = ConditionExpressionBuilder()

        self._serializer = serializer
        if serializer is None:
            self._serializer = TypeSerializer()

        self._deserializer = deserializer
        if deserializer is None:
            self._deserializer = TypeDeserializer()
Example #6
0
class TransformationInjector(object):
    """Injects the transformations into the user provided parameters."""
    def __init__(self,
                 transformer=None,
                 condition_builder=None,
                 serializer=None,
                 deserializer=None):
        self._transformer = transformer
        if transformer is None:
            self._transformer = ParameterTransformer()

        self._condition_builder = condition_builder
        if condition_builder is None:
            self._condition_builder = ConditionExpressionBuilder()

        self._serializer = serializer
        if serializer is None:
            self._serializer = TypeSerializer()

        self._deserializer = deserializer
        if deserializer is None:
            self._deserializer = TypeDeserializer()

    def inject_condition_expressions(self, params, model, **kwargs):
        """Injects the condition expression transformation into the parameters

        This injection includes transformations for ConditionExpression shapes
        and KeyExpression shapes. It also handles any placeholder names and
        values that are generated when transforming the condition expressions.
        """
        self._condition_builder.reset()
        generated_names = {}
        generated_values = {}

        # Create and apply the Condition Expression transformation.
        transformation = ConditionExpressionTransformation(
            self._condition_builder,
            placeholder_names=generated_names,
            placeholder_values=generated_values,
            is_key_condition=False)
        self._transformer.transform(params, model.input_shape, transformation,
                                    'ConditionExpression')

        # Create and apply the Key Condition Expression transformation.
        transformation = ConditionExpressionTransformation(
            self._condition_builder,
            placeholder_names=generated_names,
            placeholder_values=generated_values,
            is_key_condition=True)
        self._transformer.transform(params, model.input_shape, transformation,
                                    'KeyExpression')

        expr_attr_names_input = 'ExpressionAttributeNames'
        expr_attr_values_input = 'ExpressionAttributeValues'

        # Now that all of the condition expression transformation are done,
        # update the placeholder dictionaries in the request.
        if expr_attr_names_input in params:
            params[expr_attr_names_input].update(generated_names)
        else:
            if generated_names:
                params[expr_attr_names_input] = generated_names

        if expr_attr_values_input in params:
            params[expr_attr_values_input].update(generated_values)
        else:
            if generated_values:
                params[expr_attr_values_input] = generated_values

    def inject_attribute_value_input(self, params, model, **kwargs):
        """Injects DynamoDB serialization into parameter input"""
        self._transformer.transform(params, model.input_shape,
                                    self._serializer.serialize,
                                    'AttributeValue')

    def inject_attribute_value_output(self, parsed, model, **kwargs):
        """Injects DynamoDB deserialization into responses"""
        if model.output_shape is not None:
            self._transformer.transform(parsed, model.output_shape,
                                        self._deserializer.deserialize,
                                        'AttributeValue')
Example #7
0
 def setUp(self):
     self.builder = ConditionExpressionBuilder()
Example #8
0
class TestConditionExpressionBuilder(unittest.TestCase):
    def setUp(self):
        self.builder = ConditionExpressionBuilder()

    def assert_condition_expression_build(self,
                                          condition,
                                          ref_string,
                                          ref_names,
                                          ref_values,
                                          is_key_condition=False):
        exp_string, names, values = self.builder.build_expression(
            condition, is_key_condition=is_key_condition)
        self.assertEqual(exp_string, ref_string)
        self.assertEqual(names, ref_names)
        self.assertEqual(values, ref_values)

    def test_bad_input(self):
        a = Attr('myattr')
        with self.assertRaises(DynamoDBNeedsConditionError):
            self.builder.build_expression(a)

    def test_build_expression_eq(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.eq('foo'), '#n0 = :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_reset(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.eq('foo'), '#n0 = :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

        self.assert_condition_expression_build(a.eq('foo'), '#n1 = :v1',
                                               {'#n1': 'myattr'},
                                               {':v1': 'foo'})

        self.builder.reset()
        self.assert_condition_expression_build(a.eq('foo'), '#n0 = :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_lt(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.lt('foo'), '#n0 < :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_lte(self):
        a1 = Attr('myattr')
        self.assert_condition_expression_build(a1.lte('foo'), '#n0 <= :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_gt(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.gt('foo'), '#n0 > :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_gte(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.gte('foo'), '#n0 >= :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_begins_with(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.begins_with('foo'),
                                               'begins_with(#n0, :v0)',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_between(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.between('foo', 'foo2'),
                                               '#n0 BETWEEN :v0 AND :v1',
                                               {'#n0': 'myattr'}, {
                                                   ':v0': 'foo',
                                                   ':v1': 'foo2'
                                               })

    def test_build_expression_ne(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.ne('foo'), '#n0 <> :v0',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_expression_in(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.is_in([1, 2, 3]),
                                               '#n0 IN (:v0, :v1, :v2)',
                                               {'#n0': 'myattr'}, {
                                                   ':v0': 1,
                                                   ':v1': 2,
                                                   ':v2': 3
                                               })

    def test_build_expression_exists(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.exists(),
                                               'attribute_exists(#n0)',
                                               {'#n0': 'myattr'}, {})

    def test_build_expression_not_exists(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.not_exists(),
                                               'attribute_not_exists(#n0)',
                                               {'#n0': 'myattr'}, {})

    def test_build_contains(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.contains('foo'),
                                               'contains(#n0, :v0)',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_size(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.size(), 'size(#n0)',
                                               {'#n0': 'myattr'}, {})

    def test_build_size_with_other_conditons(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.size().eq(5),
                                               'size(#n0) = :v0',
                                               {'#n0': 'myattr'}, {':v0': 5})

    def test_build_attribute_type(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(a.attribute_type('foo'),
                                               'attribute_type(#n0, :v0)',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_and(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            a.eq('foo') & a2.eq('bar'), '(#n0 = :v0 AND #n1 = :v1)', {
                '#n0': 'myattr',
                '#n1': 'myattr2'
            }, {
                ':v0': 'foo',
                ':v1': 'bar'
            })

    def test_build_or(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            a.eq('foo') | a2.eq('bar'), '(#n0 = :v0 OR #n1 = :v1)', {
                '#n0': 'myattr',
                '#n1': 'myattr2'
            }, {
                ':v0': 'foo',
                ':v1': 'bar'
            })

    def test_build_not(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(~a.eq('foo'), '(NOT #n0 = :v0)',
                                               {'#n0': 'myattr'},
                                               {':v0': 'foo'})

    def test_build_attribute_with_attr_value(self):
        a = Attr('myattr')
        value = Attr('myreference')
        self.assert_condition_expression_build(a.eq(value), '#n0 = #n1', {
            '#n0': 'myattr',
            '#n1': 'myreference'
        }, {})

    def test_build_with_is_key_condition(self):
        k = Key('myattr')
        self.assert_condition_expression_build(k.eq('foo'),
                                               '#n0 = :v0', {'#n0': 'myattr'},
                                               {':v0': 'foo'},
                                               is_key_condition=True)

    def test_build_with_is_key_condition_throws_error(self):
        a = Attr('myattr')
        with self.assertRaises(DynamoDBNeedsKeyConditionError):
            self.builder.build_expression(a.eq('foo'), is_key_condition=True)

    def test_build_attr_map(self):
        a = Attr('MyMap.MyKey')
        self.assert_condition_expression_build(a.eq('foo'), '#n0.#n1 = :v0', {
            '#n0': 'MyMap',
            '#n1': 'MyKey'
        }, {':v0': 'foo'})

    def test_build_attr_list(self):
        a = Attr('MyList[0]')
        self.assert_condition_expression_build(a.eq('foo'), '#n0[0] = :v0',
                                               {'#n0': 'MyList'},
                                               {':v0': 'foo'})

    def test_build_nested_attr_map_list(self):
        a = Attr('MyMap.MyList[2].MyElement')
        self.assert_condition_expression_build(a.eq('foo'),
                                               '#n0.#n1[2].#n2 = :v0', {
                                                   '#n0': 'MyMap',
                                                   '#n1': 'MyList',
                                                   '#n2': 'MyElement'
                                               }, {':v0': 'foo'})

    def test_build_double_nested_and_or(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            (a.eq('foo') & a2.eq('foo2')) | (a.eq('bar') & a2.eq('bar2')),
            '((#n0 = :v0 AND #n1 = :v1) OR (#n2 = :v2 AND #n3 = :v3))', {
                '#n0': 'myattr',
                '#n1': 'myattr2',
                '#n2': 'myattr',
                '#n3': 'myattr2'
            }, {
                ':v0': 'foo',
                ':v1': 'foo2',
                ':v2': 'bar',
                ':v3': 'bar2'
            })
Example #9
0
 def setUp(self):
     self.builder = ConditionExpressionBuilder()
Example #10
0
class TestConditionExpressionBuilder(unittest.TestCase):
    def setUp(self):
        self.builder = ConditionExpressionBuilder()

    def assert_condition_expression_build(
            self, condition, ref_string, ref_names, ref_values,
            is_key_condition=False):
        exp_string, names, values = self.builder.build_expression(
            condition, is_key_condition=is_key_condition)
        self.assertEqual(exp_string, ref_string)
        self.assertEqual(names, ref_names)
        self.assertEqual(values, ref_values)

    def test_bad_input(self):
        a = Attr('myattr')
        with self.assertRaises(DynamoDBNeedsConditionError):
            self.builder.build_expression(a)

    def test_build_expression_eq(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0 = :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_reset(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0 = :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

        self.assert_condition_expression_build(
            a.eq('foo'), '#n1 = :v1', {'#n1': 'myattr'}, {':v1': 'foo'})

        self.builder.reset()
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0 = :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_lt(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.lt('foo'), '#n0 < :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_lte(self):
        a1 = Attr('myattr')
        self.assert_condition_expression_build(
            a1.lte('foo'), '#n0 <= :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_gt(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.gt('foo'), '#n0 > :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_gte(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.gte('foo'), '#n0 >= :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_begins_with(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.begins_with('foo'), 'begins_with(#n0, :v0)',
            {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_between(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.between('foo', 'foo2'), '#n0 BETWEEN :v0 AND :v1',
            {'#n0': 'myattr'}, {':v0': 'foo', ':v1': 'foo2'})

    def test_build_expression_ne(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.ne('foo'), '#n0 <> :v0', {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_expression_in(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.is_in([1, 2, 3]), '#n0 IN (:v0, :v1, :v2)',
            {'#n0': 'myattr'}, {':v0': 1, ':v1': 2, ':v2': 3})

    def test_build_expression_exists(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.exists(), 'attribute_exists(#n0)', {'#n0': 'myattr'}, {})

    def test_build_expression_not_exists(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.not_exists(), 'attribute_not_exists(#n0)', {'#n0': 'myattr'}, {})

    def test_build_contains(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.contains('foo'), 'contains(#n0, :v0)',
            {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_size(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.size(), 'size(#n0)', {'#n0': 'myattr'}, {})

    def test_build_size_with_other_conditons(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.size().eq(5), 'size(#n0) = :v0', {'#n0': 'myattr'}, {':v0': 5})

    def test_build_attribute_type(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            a.attribute_type('foo'), 'attribute_type(#n0, :v0)',
            {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_and(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            a.eq('foo') & a2.eq('bar'), '(#n0 = :v0 AND #n1 = :v1)',
            {'#n0': 'myattr', '#n1': 'myattr2'}, {':v0': 'foo', ':v1': 'bar'})

    def test_build_or(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            a.eq('foo') | a2.eq('bar'), '(#n0 = :v0 OR #n1 = :v1)',
            {'#n0': 'myattr', '#n1': 'myattr2'}, {':v0': 'foo', ':v1': 'bar'})

    def test_build_not(self):
        a = Attr('myattr')
        self.assert_condition_expression_build(
            ~a.eq('foo'), '(NOT #n0 = :v0)',
            {'#n0': 'myattr'}, {':v0': 'foo'})

    def test_build_attribute_with_attr_value(self):
        a = Attr('myattr')
        value = Attr('myreference')
        self.assert_condition_expression_build(
            a.eq(value), '#n0 = #n1',
            {'#n0': 'myattr', '#n1': 'myreference'}, {})

    def test_build_with_is_key_condition(self):
        k = Key('myattr')
        self.assert_condition_expression_build(
            k.eq('foo'), '#n0 = :v0',
            {'#n0': 'myattr'}, {':v0': 'foo'}, is_key_condition=True)

    def test_build_with_is_key_condition_throws_error(self):
        a = Attr('myattr')
        with self.assertRaises(DynamoDBNeedsKeyConditionError):
            self.builder.build_expression(a.eq('foo'), is_key_condition=True)

    def test_build_attr_map(self):
        a = Attr('MyMap.MyKey')
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0.#n1 = :v0', {'#n0': 'MyMap', '#n1': 'MyKey'},
            {':v0': 'foo'})

    def test_build_attr_list(self):
        a = Attr('MyList[0]')
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0[0] = :v0', {'#n0': 'MyList'}, {':v0': 'foo'})

    def test_build_nested_attr_map_list(self):
        a = Attr('MyMap.MyList[2].MyElement')
        self.assert_condition_expression_build(
            a.eq('foo'), '#n0.#n1[2].#n2 = :v0',
            {'#n0': 'MyMap', '#n1': 'MyList', '#n2': 'MyElement'},
            {':v0': 'foo'})

    def test_build_double_nested_and_or(self):
        a = Attr('myattr')
        a2 = Attr('myattr2')
        self.assert_condition_expression_build(
            (a.eq('foo') & a2.eq('foo2')) | (a.eq('bar') & a2.eq('bar2')),
            '((#n0 = :v0 AND #n1 = :v1) OR (#n2 = :v2 AND #n3 = :v3))',
            {'#n0': 'myattr', '#n1': 'myattr2', '#n2': 'myattr',
             '#n3': 'myattr2'},
            {':v0': 'foo', ':v1': 'foo2', ':v2': 'bar', ':v3': 'bar2'})
Example #11
0
class TestConditionExpressionBuilder(unittest.TestCase):
    def setUp(self):
        self.builder = ConditionExpressionBuilder()

    def assert_condition_expression_build(self, condition, ref_string, ref_names, ref_values, is_key_condition=False):
        exp_string, names, values = self.builder.build_expression(condition, is_key_condition=is_key_condition)
        self.assertEqual(exp_string, ref_string)
        self.assertEqual(names, ref_names)
        self.assertEqual(values, ref_values)

    def test_bad_input(self):
        a = Attr("myattr")
        with self.assertRaises(DynamoDBNeedsConditionError):
            self.builder.build_expression(a)

    def test_build_expression_eq(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.eq("foo"), "#n0 = :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_reset(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.eq("foo"), "#n0 = :v0", {"#n0": "myattr"}, {":v0": "foo"})

        self.assert_condition_expression_build(a.eq("foo"), "#n1 = :v1", {"#n1": "myattr"}, {":v1": "foo"})

        self.builder.reset()
        self.assert_condition_expression_build(a.eq("foo"), "#n0 = :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_lt(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.lt("foo"), "#n0 < :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_lte(self):
        a1 = Attr("myattr")
        self.assert_condition_expression_build(a1.lte("foo"), "#n0 <= :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_gt(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.gt("foo"), "#n0 > :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_gte(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.gte("foo"), "#n0 >= :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_begins_with(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(
            a.begins_with("foo"), "begins_with(#n0, :v0)", {"#n0": "myattr"}, {":v0": "foo"}
        )

    def test_build_expression_between(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(
            a.between("foo", "foo2"), "#n0 BETWEEN :v0 AND :v1", {"#n0": "myattr"}, {":v0": "foo", ":v1": "foo2"}
        )

    def test_build_expression_ne(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.ne("foo"), "#n0 <> :v0", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_expression_in(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(
            a.is_in([1, 2, 3]), "#n0 IN (:v0, :v1, :v2)", {"#n0": "myattr"}, {":v0": 1, ":v1": 2, ":v2": 3}
        )

    def test_build_expression_exists(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.exists(), "attribute_exists(#n0)", {"#n0": "myattr"}, {})

    def test_build_expression_not_exists(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.not_exists(), "attribute_not_exists(#n0)", {"#n0": "myattr"}, {})

    def test_build_contains(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(
            a.contains("foo"), "contains(#n0, :v0)", {"#n0": "myattr"}, {":v0": "foo"}
        )

    def test_build_size(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.size(), "size(#n0)", {"#n0": "myattr"}, {})

    def test_build_size_with_other_conditons(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(a.size().eq(5), "size(#n0) = :v0", {"#n0": "myattr"}, {":v0": 5})

    def test_build_attribute_type(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(
            a.attribute_type("foo"), "attribute_type(#n0, :v0)", {"#n0": "myattr"}, {":v0": "foo"}
        )

    def test_build_and(self):
        a = Attr("myattr")
        a2 = Attr("myattr2")
        self.assert_condition_expression_build(
            a.eq("foo") & a2.eq("bar"),
            "(#n0 = :v0 AND #n1 = :v1)",
            {"#n0": "myattr", "#n1": "myattr2"},
            {":v0": "foo", ":v1": "bar"},
        )

    def test_build_or(self):
        a = Attr("myattr")
        a2 = Attr("myattr2")
        self.assert_condition_expression_build(
            a.eq("foo") | a2.eq("bar"),
            "(#n0 = :v0 OR #n1 = :v1)",
            {"#n0": "myattr", "#n1": "myattr2"},
            {":v0": "foo", ":v1": "bar"},
        )

    def test_build_not(self):
        a = Attr("myattr")
        self.assert_condition_expression_build(~a.eq("foo"), "(NOT #n0 = :v0)", {"#n0": "myattr"}, {":v0": "foo"})

    def test_build_attribute_with_attr_value(self):
        a = Attr("myattr")
        value = Attr("myreference")
        self.assert_condition_expression_build(a.eq(value), "#n0 = #n1", {"#n0": "myattr", "#n1": "myreference"}, {})

    def test_build_with_is_key_condition(self):
        k = Key("myattr")
        self.assert_condition_expression_build(
            k.eq("foo"), "#n0 = :v0", {"#n0": "myattr"}, {":v0": "foo"}, is_key_condition=True
        )

    def test_build_with_is_key_condition_throws_error(self):
        a = Attr("myattr")
        with self.assertRaises(DynamoDBNeedsKeyConditionError):
            self.builder.build_expression(a.eq("foo"), is_key_condition=True)

    def test_build_attr_map(self):
        a = Attr("MyMap.MyKey")
        self.assert_condition_expression_build(
            a.eq("foo"), "#n0.#n1 = :v0", {"#n0": "MyMap", "#n1": "MyKey"}, {":v0": "foo"}
        )

    def test_build_attr_list(self):
        a = Attr("MyList[0]")
        self.assert_condition_expression_build(a.eq("foo"), "#n0[0] = :v0", {"#n0": "MyList"}, {":v0": "foo"})

    def test_build_nested_attr_map_list(self):
        a = Attr("MyMap.MyList[2].MyElement")
        self.assert_condition_expression_build(
            a.eq("foo"), "#n0.#n1[2].#n2 = :v0", {"#n0": "MyMap", "#n1": "MyList", "#n2": "MyElement"}, {":v0": "foo"}
        )

    def test_build_double_nested_and_or(self):
        a = Attr("myattr")
        a2 = Attr("myattr2")
        self.assert_condition_expression_build(
            (a.eq("foo") & a2.eq("foo2")) | (a.eq("bar") & a2.eq("bar2")),
            "((#n0 = :v0 AND #n1 = :v1) OR (#n2 = :v2 AND #n3 = :v3))",
            {"#n0": "myattr", "#n1": "myattr2", "#n2": "myattr", "#n3": "myattr2"},
            {":v0": "foo", ":v1": "foo2", ":v2": "bar", ":v3": "bar2"},
        )
Example #12
0
class TransformationInjector(object):
    """Injects the transformations into the user provided parameters."""
    def __init__(self, transformer=None, condition_builder=None,
                 serializer=None, deserializer=None):
        self._transformer = transformer
        if transformer is None:
            self._transformer = ParameterTransformer()

        self._condition_builder = condition_builder
        if condition_builder is None:
            self._condition_builder = ConditionExpressionBuilder()

        self._serializer = serializer
        if serializer is None:
            self._serializer = TypeSerializer()

        self._deserializer = deserializer
        if deserializer is None:
            self._deserializer = TypeDeserializer()

    def inject_condition_expressions(self, params, model, **kwargs):
        """Injects the condition expression transformation into the parameters

        This injection includes transformations for ConditionExpression shapes
        and KeyExpression shapes. It also handles any placeholder names and
        values that are generated when transforming the condition expressions.
        """
        self._condition_builder.reset()
        generated_names = {}
        generated_values = {}

        # Create and apply the Condition Expression transformation.
        transformation = ConditionExpressionTransformation(
            self._condition_builder,
            placeholder_names=generated_names,
            placeholder_values=generated_values,
            is_key_condition=False
        )
        self._transformer.transform(
            params, model.input_shape, transformation,
            'ConditionExpression')

        # Create and apply the Key Condition Expression transformation.
        transformation = ConditionExpressionTransformation(
            self._condition_builder,
            placeholder_names=generated_names,
            placeholder_values=generated_values,
            is_key_condition=True
        )
        self._transformer.transform(
            params, model.input_shape, transformation,
            'KeyExpression')

        expr_attr_names_input = 'ExpressionAttributeNames'
        expr_attr_values_input = 'ExpressionAttributeValues'

        # Now that all of the condition expression transformation are done,
        # update the placeholder dictionaries in the request.
        if expr_attr_names_input in params:
            params[expr_attr_names_input].update(generated_names)
        else:
            if generated_names:
                params[expr_attr_names_input] = generated_names

        if expr_attr_values_input in params:
            params[expr_attr_values_input].update(generated_values)
        else:
            if generated_values:
                params[expr_attr_values_input] = generated_values

    def inject_attribute_value_input(self, params, model, **kwargs):
        """Injects DynamoDB serialization into parameter input"""
        self._transformer.transform(
            params, model.input_shape, self._serializer.serialize,
            'AttributeValue')

    def inject_attribute_value_output(self, parsed, model, **kwargs):
        """Injects DynamoDB deserialization into responses"""
        if model.output_shape is not None:
            self._transformer.transform(
                parsed, model.output_shape, self._deserializer.deserialize,
                'AttributeValue'
            )