def test_execution_of_if_not_exists_with_non_existing_attribute_should_return_value(
    table, ):
    update_expression = "SET a = if_not_exists(b, :val)"
    update_expression_values = {":val": {"N": "4"}}
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={"id": {
            "S": "1"
        }},
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=update_expression_values,
        item=item,
        table=table,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "4"
            }
        },
    )
    assert expected_item == item
Example #2
0
def test_execution_of_add_set_to_a_number(table):
    update_expression = "add s :value"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "N": "5"
            },
        },
    )
    try:
        validated_ast = UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={
                ":value": {
                    "SS": ["s1"]
                }
            },
            item=item,
            table=table,
        ).validate()
        UpdateExpressionExecutor(validated_ast, item, None).execute()
        expected_item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "foo2"
                },
                "s": {
                    "N": "15"
                }
            },
        )
        assert expected_item == item
        assert False
    except IncorrectDataType:
        assert True
Example #3
0
def test_validation_of_if_not_exists_not_existing_value():
    update_expression = "SET a = if_not_exists(b, a)"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "S": "A"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"S": "A"})
Example #4
0
def test_validation_of_update_expression_with_keyword(table):
    try:
        update_expression = "SET myNum = path + :val"
        update_expression_values = {":val": {"N": "3"}}
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "path": {
                    "N": "3"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=update_expression_values,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except AttributeIsReservedKeyword as e:
        assert e.keyword == "path"
Example #5
0
def test_valid_update_expression(table):
    update_expression = "set forum_name=:NewName, forum_type=:NewType"
    update_expression_values = {
        ":NewName": {
            "S": "AmazingForum"
        },
        ":NewType": {
            "S": "BASIC"
        },
    }
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "forum_name"}),
        hash_key_type="TYPE",
        range_key=DynamoType({"S": "forum_type"}),
        range_key_type="TYPE",
        attrs={"forum_name": {
            "S": "hello"
        }},
    )
    UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=update_expression_values,
        item=item,
        table=table,
    ).validate()
Example #6
0
def test_execution_of_delete_element_from_a_string_attribute():
    """A delete statement must use a value of type SS in order to delete elements from a set."""
    update_expression = "delete s :value"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "S": "5"
            },
        },
    )
    try:
        validated_ast = UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={
                ":value": {
                    "SS": ["value2"]
                }
            },
            item=item,
        ).validate()
        UpdateExpressionExecutor(validated_ast, item, None).execute()
        assert False, "Must raise exception"
    except IncorrectDataType:
        assert True
Example #7
0
def test_validation_of_update_expression_with_attribute_that_does_not_exist_in_item(
    table, ):
    """
    When an update expression tries to get an attribute that does not exist it must throw the appropriate exception.

    An error occurred (ValidationException) when calling the UpdateItem operation:
    The provided expression refers to an attribute that does not exist in the item
    """
    try:
        update_expression = "SET a = nonexistent"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "path": {
                    "N": "3"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except AttributeDoesNotExist:
        assert True
Example #8
0
def test_validation_of_if_not_exists_with_existing_attribute_should_return_value(
        table):
    update_expression = "SET a = if_not_exists(b, :val)"
    update_expression_values = {":val": {"N": "4"}}
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "b": {
                "N": "3"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=update_expression_values,
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "3"})
Example #9
0
def test_execution_of__delete_element_from_set_invalid_value(
        expression_attribute_values, unexpected_data_type):
    """A delete statement must use a value of type SS in order to delete elements from a set."""
    update_expression = "delete s :value"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "SS": ["value1", "value2", "value3"]
            },
        },
    )
    try:
        validated_ast = UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=expression_attribute_values,
            item=item,
        ).validate()
        UpdateExpressionExecutor(validated_ast, item, None).execute()
        assert False, "Must raise exception"
    except IncorrectOperandType as e:
        assert e.operator_or_function == "operator: DELETE"
        assert e.operand_type == unexpected_data_type
Example #10
0
def test_validation_of_a_set_statement_with_incorrect_passed_value(
    update_expression, table
):
    """
    By running permutations it shows that values are replaced prior to resolving attributes.

    An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression:
    An expression attribute value used in expression is not defined; attribute value: :val2
    """
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={"id": {"S": "1"}, "b": {"N": "3"}},
    )
    try:
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names={"#b": "ok"},
            expression_attribute_values={":val": {"N": "3"}},
            item=item,
            table=table,
        ).validate()
    except ExpressionAttributeValueNotDefined as e:
        assert e.attribute_value == ":val2"
Example #11
0
def test_validation_set_path_does_not_need_to_be_resolvable_when_setting_a_new_attribute(
    table, ):
    """If this step just passes we are happy enough"""
    update_expression = "set d=a"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "a": {
                "N": "3"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "3"})
Example #12
0
def test_sum_with_incompatible_types(table):
    """
    Must error out:
    Invalid UpdateExpression: Incorrect operand type for operator or function; operator or function: +, operand type: S'
    Returns:

    """
    try:
        update_expression = "SET ri = :val + :val2"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={"id": {"S": "1"}, "ri": {"L": [{"S": "i1"}, {"S": "i2"}]}},
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={":val": {"S": "N"}, ":val2": {"N": "3"}},
            item=item,
            table=table,
        ).validate()
    except IncorrectOperandType as e:
        assert e.operand_type == "S"
        assert e.operator_or_function == "+"
Example #13
0
def test_cannot_index_into_a_string(table):
    """
    Must error out:
    The document path provided in the update expression is invalid for update'
    """
    try:
        update_expression = "set itemstr[1]=:Item"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={"id": {"S": "foo2"}, "itemstr": {"S": "somestring"}},
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={":Item": {"S": "string_update"}},
            item=item,
            table=table,
        ).validate()
        assert False, "Must raise exception"
    except InvalidUpdateExpressionInvalidDocumentPath:
        assert True
Example #14
0
def test_validation_of_update_expression_with_attribute_name_that_is_not_defined(
    update_expression, table,
):
    """
    When an update expression tries to get an attribute name that is not provided it must throw an exception.

    An error occurred (ValidationException) when calling the UpdateItem operation: Invalid UpdateExpression:
    An expression attribute name used in the document path is not defined; attribute name: #c
    """
    try:
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={"id": {"S": "1"}, "path": {"N": "3"}},
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names={"#b": "ok"},
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except ExpressionAttributeNameNotDefined as e:
        assert e.not_defined_attribute_name == "#c"
Example #15
0
def test_validation_of_sum_operation(table):
    update_expression = "SET a = a + b"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "3"
            },
            "b": {
                "N": "4"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType({"N": "7"})
Example #16
0
def test_validation_set_path_does_not_need_to_be_resolvable_but_must_be_creatable_when_setting_a_new_attribute(
    table, ):
    try:
        update_expression = "set d.e=a"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "foo2"
                },
                "a": {
                    "N": "3"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "Must raise exception"
    except InvalidUpdateExpressionInvalidDocumentPath:
        assert True
Example #17
0
def test_validation_of_if_not_exists_not_existing_invalid_replace_value(table):
    try:
        update_expression = "SET a = if_not_exists(b, a.c)"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "a": {
                    "S": "A"
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=None,
            item=item,
            table=table,
        ).validate()
        assert False, "No exception raised"
    except AttributeDoesNotExist:
        assert True
Example #18
0
def test_execution_of_if_not_exists_with_existing_attribute_should_return_attribute(
):
    update_expression = "SET a = if_not_exists(b, a)"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "S": "A"
            },
            "b": {
                "S": "B"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "S": "B"
            },
            "b": {
                "S": "B"
            }
        },
    )
    assert expected_item == item
Example #19
0
def test_execution_of_sum_operation():
    update_expression = "SET a = a + b"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "3"
            },
            "b": {
                "N": "4"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "7"
            },
            "b": {
                "N": "4"
            }
        },
    )
    assert expected_item == item
Example #20
0
def test_execution_of_add_to_a_set(table):
    update_expression = "ADD s :value"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "SS": ["value1", "value2", "value3"]
            },
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values={
            ":value": {
                "SS": ["value2", "value5"]
            }
        },
        item=item,
        table=table,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "SS": ["value1", "value2", "value3", "value5"]
            },
        },
    )
    assert expected_item == item
Example #21
0
def test_execution_of_add_number():
    update_expression = "add s :value"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "N": "5"
            },
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values={
            ":value": {
                "N": "10"
            }
        },
        item=item,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "N": "15"
            }
        },
    )
    assert expected_item == item
Example #22
0
def test_execution_of_remove(table):
    update_expression = "Remove a"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "1"
            },
            "a": {
                "N": "3"
            },
            "b": {
                "N": "4"
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
        table=table,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "1"
            },
            "b": {
                "N": "4"
            }
        },
    )
    assert expected_item == item
Example #23
0
def test_validation_homogeneous_list_append_function(table):
    update_expression = "SET ri = list_append(ri, :vals)"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "1"
            },
            "ri": {
                "L": [{
                    "S": "i1"
                }, {
                    "S": "i2"
                }]
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values={
            ":vals": {
                "L": [{
                    "S": "i3"
                }, {
                    "S": "i4"
                }]
            }
        },
        item=item,
        table=table,
    ).validate()
    dynamo_value = get_set_action_value(validated_ast)
    assert dynamo_value == DynamoType(
        {"L": [{
            "S": "i1"
        }, {
            "S": "i2"
        }, {
            "S": "i3"
        }, {
            "S": "i4"
        }]})
Example #24
0
def test_validation_of_empty_string_key_val(table):
    with pytest.raises(EmptyKeyAttributeException):
        update_expression = "set forum_name=:NewName"
        update_expression_values = {":NewName": {"S": ""}}
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "forum_name"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={"forum_name": {"S": "hello"}},
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values=update_expression_values,
            item=item,
            table=table,
        ).validate()
Example #25
0
def test_validation_list_append_function_with_non_list_arg():
    """
    Must error out:
    Invalid UpdateExpression: Incorrect operand type for operator or function;
     operator or function: list_append, operand type: S'
    Returns:

    """
    try:
        update_expression = "SET ri = list_append(ri, :vals)"
        update_expression_ast = UpdateExpressionParser.make(update_expression)
        item = Item(
            hash_key=DynamoType({"S": "id"}),
            hash_key_type="TYPE",
            range_key=None,
            range_key_type=None,
            attrs={
                "id": {
                    "S": "1"
                },
                "ri": {
                    "L": [{
                        "S": "i1"
                    }, {
                        "S": "i2"
                    }]
                }
            },
        )
        UpdateExpressionValidator(
            update_expression_ast,
            expression_attribute_names=None,
            expression_attribute_values={
                ":vals": {
                    "S": "N"
                }
            },
            item=item,
        ).validate()
    except IncorrectOperandType as e:
        assert e.operand_type == "S"
        assert e.operator_or_function == "list_append"
Example #26
0
def test_execution_of_remove_in_list():
    update_expression = "Remove itemmap.itemlist[1]"
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "itemmap": {
                "M": {
                    "itemlist": {
                        "L": [
                            {
                                "M": {
                                    "foo00": {
                                        "S": "bar1"
                                    },
                                    "foo01": {
                                        "S": "bar2"
                                    }
                                }
                            },
                            {
                                "M": {
                                    "foo10": {
                                        "S": "bar1"
                                    },
                                    "foo11": {
                                        "S": "bar2"
                                    }
                                }
                            },
                        ]
                    }
                }
            },
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=None,
        expression_attribute_values=None,
        item=item,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item, None).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        hash_key_type="TYPE",
        range_key=None,
        range_key_type=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "itemmap": {
                "M": {
                    "itemlist": {
                        "L": [
                            {
                                "M": {
                                    "foo00": {
                                        "S": "bar1"
                                    },
                                    "foo01": {
                                        "S": "bar2"
                                    }
                                }
                            },
                        ]
                    }
                }
            },
        },
    )
    assert expected_item == item
Example #27
0
def test_execution_of_delete_element_from_set(table, attr_name):
    expression_attribute_names = {"#placeholder": "s"}
    update_expression = "delete {} :value".format(attr_name)
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "SS": ["value1", "value2", "value3"]
            }
        },
    )
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=expression_attribute_names,
        expression_attribute_values={
            ":value": {
                "SS": ["value2", "value5"]
            }
        },
        item=item,
        table=table,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item,
                             expression_attribute_names).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={
            "id": {
                "S": "foo2"
            },
            "s": {
                "SS": ["value1", "value3"]
            },
        },
    )
    assert expected_item == item

    # delete last elements
    update_expression = "delete {} :value".format(attr_name)
    update_expression_ast = UpdateExpressionParser.make(update_expression)
    validated_ast = UpdateExpressionValidator(
        update_expression_ast,
        expression_attribute_names=expression_attribute_names,
        expression_attribute_values={
            ":value": {
                "SS": ["value1", "value3"]
            }
        },
        item=item,
        table=table,
    ).validate()
    UpdateExpressionExecutor(validated_ast, item,
                             expression_attribute_names).execute()
    expected_item = Item(
        hash_key=DynamoType({"S": "id"}),
        range_key=None,
        attrs={"id": {
            "S": "foo2"
        }},
    )
    assert expected_item == item