Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat: Close #107 Allow empty char values to be converted to null
  • Loading branch information
EliuX committed Apr 25, 2020
commit 7dc262f3a61f541a3cb6ba3293ee7c57a5aa96f2
9 changes: 8 additions & 1 deletion commons/data_access_layer/cosmos_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,14 @@ def check_visibility(item, throw_not_found_if_deleted):
if throw_not_found_if_deleted and item.get('deleted') is not None:
raise exceptions.CosmosResourceNotFoundError(message='Deleted item',
status_code=404)

return item

@staticmethod
def replace_empty_value_per_none(item_data: dict) -> dict:
for k, v in item_data.items():
if isinstance(v, str) and len(v) == 0:
item_data[k] = None

def create(self, data: dict, mapper: Callable = None):
self.on_create(data)
function_mapper = self.get_mapper_or_dict(mapper)
Expand Down Expand Up @@ -207,6 +212,8 @@ def on_create(self, new_item_data: dict):
if new_item_data.get('id') is None:
new_item_data['id'] = generate_uuid4()

self.replace_empty_value_per_none(new_item_data)

def on_update(self, update_item_data: dict):
pass

Expand Down
25 changes: 25 additions & 0 deletions tests/commons/data_access_layer/cosmos_db_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,3 +602,28 @@ def test_datetime_str_comparison():

assert now_str > datetime_str(now - timedelta(days=1))
assert now_str < datetime_str(now + timedelta(days=1))


def test_replace_empty_value_per_none(tenant_id: str):
initial_value = dict(id=fake.uuid4(),
name=fake.name(),
empty_str_attrib="",
array_attrib=[1, 2, 3],
empty_array_attrib=[],
description=" ",
age=fake.pyint(min_value=10, max_value=80),
size=0,
tenant_id=tenant_id)

input = initial_value.copy()

CosmosDBRepository.replace_empty_value_per_none(input)

assert input["name"] == initial_value["name"]
assert input["empty_str_attrib"] is None
assert input["array_attrib"] == initial_value["array_attrib"]
assert input["empty_array_attrib"] == initial_value["empty_array_attrib"]
assert input["description"] == initial_value["description"]
assert input["age"] == initial_value["age"]
assert input["size"] == initial_value["size"]
assert input["tenant_id"] == initial_value["tenant_id"]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from flask import json
from flask.testing import FlaskClient
from flask_restplus._http import HTTPStatus
from pytest_mock import MockFixture
from pytest_mock import MockFixture, pytest

from commons.data_access_layer.cosmos_db import current_datetime, current_datetime_str

Expand Down Expand Up @@ -423,3 +423,50 @@ def test_get_running_should_return_not_found_if_find_running_throws_StopIteratio
assert HTTPStatus.NOT_FOUND == response.status_code
repository_update_mock.assert_called_once_with(partition_key_value=tenant_id,
owner_id=owner_id)

@pytest.mark.parametrize(
'invalid_uuid', ["zxy", "zxy%s" % fake.uuid4(), "%szxy" % fake.uuid4(), " "]
)
def test_create_with_invalid_uuid_format_should_return_bad_request(client: FlaskClient,
mocker: MockFixture,
valid_header: dict,
invalid_uuid: str):
from time_tracker_api.time_entries.time_entries_namespace import time_entries_dao
repository_container_create_item_mock = mocker.patch.object(time_entries_dao.repository.container,
'create_item',
return_value=fake_time_entry)
invalid_time_entry_input = {
"project_id": fake.uuid4(),
"activity_id": invalid_uuid,
}
response = client.post("/time-entries",
headers=valid_header,
json=invalid_time_entry_input,
follow_redirects=True)

assert HTTPStatus.BAD_REQUEST == response.status_code
repository_container_create_item_mock.assert_not_called()

@pytest.mark.parametrize(
'valid_uuid', ["", fake.uuid4()]
)
def test_create_with_valid_uuid_format_should_return_created(client: FlaskClient,
mocker: MockFixture,
valid_header: dict,
valid_uuid: str):
from time_tracker_api.time_entries.time_entries_namespace import time_entries_dao
repository_container_create_item_mock = mocker.patch.object(time_entries_dao.repository.container,
'create_item',
return_value=fake_time_entry)
invalid_time_entry_input = {
"project_id": fake.uuid4(),
"activity_id": valid_uuid,
}
response = client.post("/time-entries",
headers=valid_header,
json=invalid_time_entry_input,
follow_redirects=True)

assert HTTPStatus.CREATED == response.status_code
repository_container_create_item_mock.assert_called()

2 changes: 1 addition & 1 deletion time_tracker_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class NullableString(fields.String):
class UUID(NullableString):
def __init__(self, *args, **kwargs):
super(UUID, self).__init__(*args, **kwargs)
self.pattern = UUID_REGEX
self.pattern = r"^(|%s)$" % UUID_REGEX


common_fields = {
Expand Down
1 change: 1 addition & 0 deletions time_tracker_api/time_entries/time_entries_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def on_create(self, new_item_data: dict):
def on_update(self, updated_item_data: dict):
CosmosDBRepository.on_update(self, updated_item_data)
self.validate_data(updated_item_data)
self.replace_empty_value_per_none(updated_item_data)

def find_interception_with_date_range(self, start_date, end_date, owner_id, partition_key_value,
ignore_id=None, visible_only=True, mapper: Callable = None):
Expand Down