Skip to content

Commit b657fc3

Browse files
refactor: TT-180 create method get activities by id list in activitydao (#265)
* refactor: TT-180 add methods find_all_with_id_in_list and get_all_with_id_in_list in ActivityCosmosDB * refactor: TT-180 changes in activity test * test: TT-180 add test validate list * test: TT-180 add test convert list to tuple string * test: TT-180 add test create sql in condition * test: TT-180 add test find_all, in progress * test: TT-180 add test find_all_with_id_in_list * test: TT-180 remove unused imports, fix quotes * refactor: TT-180 move convert_list_to_tuple_string and validate_list to utils * refactor: TT-180 delete unused method in conftest * refactor: TT-180 changes variables (id_list to ids_list) and same logic in convert_list_to_tuple_string * refactor: TT-180 delete method validate_test, rename activty_ids Co-authored-by: roberto <[email protected]>
1 parent 14c82d0 commit b657fc3

File tree

5 files changed

+191
-9
lines changed

5 files changed

+191
-9
lines changed

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
from time_tracker_api.time_entries.time_entries_repository import (
1515
TimeEntryCosmosDBRepository,
1616
)
17+
from time_tracker_api.activities.activities_model import (
18+
ActivityCosmosDBRepository,
19+
)
1720

1821
fake = Faker()
1922
Faker.seed()
@@ -222,6 +225,17 @@ def running_time_entry(
222225
)
223226

224227

228+
@pytest.fixture(scope="module")
229+
def activity_repository(app: Flask) -> ActivityCosmosDBRepository:
230+
with app.app_context():
231+
from commons.data_access_layer.cosmos_db import init_app, cosmos_helper
232+
233+
if cosmos_helper is None:
234+
init_app(app)
235+
236+
return ActivityCosmosDBRepository()
237+
238+
225239
@pytest.fixture(scope="session")
226240
def valid_jwt(app: Flask, tenant_id: str, owner_id: str) -> str:
227241
with app.app_context():
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from unittest.mock import Mock, patch
2+
import pytest
3+
4+
from commons.data_access_layer.database import EventContext
5+
from time_tracker_api.activities.activities_model import (
6+
ActivityCosmosDBRepository,
7+
ActivityCosmosDBModel,
8+
)
9+
10+
11+
@pytest.mark.parametrize(
12+
"activities_ids_list,expected_result",
13+
[
14+
(["id1"], "c.id IN ('id1')"),
15+
(["id1", "id2"], "c.id IN ('id1', 'id2')"),
16+
(["id1", "id2", "id3", "id4"], "c.id IN ('id1', 'id2', 'id3', 'id4')"),
17+
],
18+
)
19+
def test_create_sql_in_condition(
20+
activity_repository: ActivityCosmosDBRepository,
21+
activities_ids_list,
22+
expected_result,
23+
):
24+
result = activity_repository.create_sql_in_condition(activities_ids_list)
25+
assert expected_result == result
26+
27+
28+
@patch(
29+
'time_tracker_api.activities.activities_model.ActivityCosmosDBRepository.create_sql_condition_for_visibility'
30+
)
31+
@patch(
32+
'time_tracker_api.activities.activities_model.ActivityCosmosDBRepository.create_sql_in_condition'
33+
)
34+
@patch(
35+
'time_tracker_api.activities.activities_model.ActivityCosmosDBRepository.find_partition_key_value'
36+
)
37+
def test_find_all_with_id_in_list(
38+
find_partition_key_value_mock,
39+
create_sql_in_condition_mock,
40+
create_sql_condition_for_visibility_mock,
41+
event_context: EventContext,
42+
activity_repository: ActivityCosmosDBRepository,
43+
):
44+
expected_item = {
45+
'id': 'id1',
46+
'name': 'testing',
47+
'description': 'do some testing',
48+
'tenant_id': 'tenantid1',
49+
}
50+
51+
query_items_mock = Mock(return_value=[expected_item])
52+
activity_repository.container = Mock()
53+
activity_repository.container.query_items = query_items_mock
54+
55+
result = activity_repository.find_all_with_id_in_list(event_context, [])
56+
57+
create_sql_condition_for_visibility_mock.assert_called_once()
58+
create_sql_in_condition_mock.assert_called_once()
59+
find_partition_key_value_mock.assert_called_once()
60+
query_items_mock.assert_called_once()
61+
62+
assert len(result) == 1
63+
activity = result[0]
64+
assert isinstance(activity, ActivityCosmosDBModel)
65+
assert activity.__dict__ == expected_item

tests/utils/repository_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from unittest.mock import patch
2+
from utils.repository import convert_list_to_tuple_string
3+
import pytest
4+
5+
6+
@pytest.mark.parametrize(
7+
"ids_list",
8+
[
9+
123,
10+
(1, 2),
11+
"ids_list",
12+
{"ids_list": []},
13+
],
14+
)
15+
def test_convert_list_to_tuple_string_should_fail(ids_list):
16+
try:
17+
convert_list_to_tuple_string(ids_list)
18+
except Exception as e:
19+
assert type(e) is AssertionError
20+
21+
22+
@pytest.mark.parametrize(
23+
"ids_list,expected_result",
24+
[
25+
(["id1"], "('id1')"),
26+
(["id1", "id2"], "('id1', 'id2')"),
27+
(["id1", "id2", "id3", "id4"], "('id1', 'id2', 'id3', 'id4')"),
28+
],
29+
)
30+
def test_convert_list_to_tuple_string_should_success(
31+
ids_list,
32+
expected_result,
33+
):
34+
result = convert_list_to_tuple_string(ids_list)
35+
36+
assert expected_result == result

time_tracker_api/activities/activities_model.py

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22

33
from azure.cosmos import PartitionKey
44

5-
from commons.data_access_layer.cosmos_db import CosmosDBModel, CosmosDBDao, CosmosDBRepository
5+
from commons.data_access_layer.cosmos_db import (
6+
CosmosDBModel,
7+
CosmosDBDao,
8+
CosmosDBRepository,
9+
)
610
from time_tracker_api.database import CRUDDao, APICosmosDBDao
11+
from typing import List, Callable
12+
from commons.data_access_layer.database import EventContext
13+
from utils.repository import convert_list_to_tuple_string
714

815

916
class ActivityDao(CRUDDao):
@@ -17,7 +24,7 @@ class ActivityDao(CRUDDao):
1724
'uniqueKeys': [
1825
{'paths': ['/name', '/deleted']},
1926
]
20-
}
27+
},
2128
}
2229

2330

@@ -39,12 +46,63 @@ def __str___(self):
3946
return "the activity \"%s\"" % self.name # pragma: no cover
4047

4148

42-
def create_dao() -> ActivityDao:
43-
repository = CosmosDBRepository.from_definition(container_definition,
44-
mapper=ActivityCosmosDBModel)
49+
class ActivityCosmosDBRepository(CosmosDBRepository):
50+
def __init__(self):
51+
CosmosDBRepository.__init__(
52+
self,
53+
container_id=container_definition['id'],
54+
partition_key_attribute='tenant_id',
55+
mapper=ActivityCosmosDBModel,
56+
)
57+
58+
def create_sql_in_condition(self, activity_ids):
59+
id_values = convert_list_to_tuple_string(activity_ids)
60+
61+
return "c.id IN {value_condition}".format(value_condition=id_values)
62+
63+
def find_all_with_id_in_list(
64+
self,
65+
event_context: EventContext,
66+
activity_ids: List[str],
67+
visible_only=True,
68+
mapper: Callable = None,
69+
):
70+
visibility = self.create_sql_condition_for_visibility(visible_only)
71+
query_str = """
72+
SELECT * FROM c
73+
WHERE {condition}
74+
{visibility_condition}
75+
""".format(
76+
condition=self.create_sql_in_condition(activity_ids),
77+
visibility_condition=visibility,
78+
)
79+
80+
tenant_id_value = self.find_partition_key_value(event_context)
81+
result = self.container.query_items(
82+
query=query_str,
83+
partition_key=tenant_id_value,
84+
)
85+
86+
function_mapper = self.get_mapper_or_dict(mapper)
87+
return list(map(function_mapper, result))
4588

46-
class ActivityCosmosDBDao(APICosmosDBDao, ActivityDao):
47-
def __init__(self):
48-
CosmosDBDao.__init__(self, repository)
4989

50-
return ActivityCosmosDBDao()
90+
class ActivityCosmosDBDao(APICosmosDBDao, ActivityDao):
91+
def __init__(self, repository):
92+
CosmosDBDao.__init__(self, repository)
93+
94+
def get_all_with_id_in_list(
95+
self,
96+
activity_ids,
97+
):
98+
event_ctx = self.create_event_context("read-many")
99+
return self.repository.find_all_with_id_in_list(
100+
event_ctx,
101+
activity_ids,
102+
)
103+
104+
105+
def create_dao() -> ActivityDao:
106+
repository = ActivityCosmosDBRepository()
107+
108+
return ActivityCosmosDBDao(repository)

utils/repository.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
def convert_list_to_tuple_string(ids_list):
2+
assert isinstance(ids_list, list)
3+
assert len(ids_list) > 0
4+
result = (
5+
str(tuple(ids_list)).replace(",", "")
6+
if len(ids_list) == 1
7+
else str(tuple(ids_list))
8+
)
9+
return result

0 commit comments

Comments
 (0)