Skip to content

Commit f877e0a

Browse files
committed
feat: add test find_all is called with generated dates
1 parent b494a75 commit f877e0a

File tree

5 files changed

+105
-61
lines changed

5 files changed

+105
-61
lines changed

commons/data_access_layer/cosmos_db.py

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import uuid
44
from datetime import datetime
5-
from typing import Callable, List
5+
from typing import Callable, List, Tuple
66

77
import azure.cosmos.cosmos_client as cosmos_client
88
import azure.cosmos.exceptions as exceptions
@@ -117,18 +117,15 @@ def create_sql_where_conditions(conditions: dict, container_name='c') -> str:
117117
return ""
118118

119119
@staticmethod
120-
def create_sql_custom_conditions(custom_conditions: List[str]) -> str:
121-
if len(custom_conditions) > 0:
122-
return """
123-
AND {custom_conditions_clause}
124-
""".format(
125-
custom_conditions_clause=" AND ".join(custom_conditions)
126-
)
120+
def create_custom_sql_conditions(custom_sql_conditions: List[str]) -> str:
121+
if len(custom_sql_conditions) > 0:
122+
return "AND {custom_sql_conditions_clause}".format(
123+
custom_sql_conditions_clause=" AND ".join(custom_sql_conditions))
127124
else:
128125
return ''
129126

130127
@staticmethod
131-
def generate_condition_values(conditions: dict) -> dict:
128+
def generate_params(conditions: dict) -> dict:
132129
result = []
133130
for k, v in conditions.items():
134131
result.append({
@@ -165,7 +162,7 @@ def find(self, id: str, partition_key_value, peeker: 'function' = None,
165162
function_mapper = self.get_mapper_or_dict(mapper)
166163
return function_mapper(self.check_visibility(found_item, visible_only))
167164

168-
def find_all(self, partition_key_value: str, conditions: dict = {}, custom_conditions: List[str] = [],
165+
def find_all(self, partition_key_value: str, conditions: dict = {}, custom_sql_conditions: List[str] = [],
169166
custom_params: dict = {}, max_count=None, offset=0, visible_only=True, mapper: Callable = None):
170167
# TODO Use the tenant_id param and change container alias
171168
max_count = self.get_page_size_or(max_count)
@@ -174,16 +171,16 @@ def find_all(self, partition_key_value: str, conditions: dict = {}, custom_condi
174171
{"name": "@offset", "value": offset},
175172
{"name": "@max_count", "value": max_count},
176173
]
177-
params.extend(self.generate_condition_values(conditions))
174+
params.extend(self.generate_params(conditions))
178175
params.extend(custom_params)
179176
result = self.container.query_items(query="""
180177
SELECT * FROM c WHERE c.{partition_key_attribute}=@partition_key_value
181-
{conditions_clause} {visibility_condition} {custom_conditions_clause} {order_clause}
178+
{conditions_clause} {visibility_condition} {custom_sql_conditions_clause} {order_clause}
182179
OFFSET @offset LIMIT @max_count
183180
""".format(partition_key_attribute=self.partition_key_attribute,
184181
visibility_condition=self.create_sql_condition_for_visibility(visible_only),
185182
conditions_clause=self.create_sql_where_conditions(conditions),
186-
custom_conditions_clause=self.create_sql_custom_conditions(custom_conditions),
183+
custom_sql_conditions_clause=self.create_custom_sql_conditions(custom_sql_conditions),
187184
order_clause=self.create_sql_order_clause()),
188185
parameters=params,
189186
partition_key=partition_key_value,
@@ -292,3 +289,36 @@ def generate_uuid4() -> str:
292289
def init_app(app: Flask) -> None:
293290
global cosmos_helper
294291
cosmos_helper = CosmosDBFacade.from_flask_config(app)
292+
293+
294+
def get_last_day_of_month(year: int, month: int) -> int:
295+
from calendar import monthrange
296+
return monthrange(year=year, month=month)[1]
297+
298+
299+
def get_current_year() -> int:
300+
return datetime.now().year
301+
302+
303+
def get_current_month() -> int:
304+
return datetime.now().month
305+
306+
307+
def get_date_range_of_month(
308+
year: int,
309+
month: int
310+
) -> Tuple[datetime, datetime]:
311+
first_day_of_month = 1
312+
start_date = datetime(year=year, month=month, day=first_day_of_month)
313+
314+
last_day_of_month = get_last_day_of_month(year=year, month=month)
315+
end_date = datetime(
316+
year=year,
317+
month=month,
318+
day=last_day_of_month,
319+
hour=23,
320+
minute=59,
321+
second=59,
322+
microsecond=999999
323+
)
324+
return start_date, end_date

tests/commons/data_access_layer/cosmos_db_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ def test_repository_create_sql_where_conditions_with_no_values(cosmos_db_reposit
559559

560560

561561
def test_repository_append_conditions_values(cosmos_db_repository: CosmosDBRepository):
562-
result = cosmos_db_repository.generate_condition_values({'owner_id': 'mark', 'customer_id': 'ioet'})
562+
result = cosmos_db_repository.generate_params({'owner_id': 'mark', 'customer_id': 'ioet'})
563563

564564
assert result is not None
565565
assert result == [{'name': '@owner_id', 'value': 'mark'},

tests/time_tracker_api/time_entries/time_entries_namespace_test.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
from flask_restplus._http import HTTPStatus
88
from pytest_mock import MockFixture, pytest
99

10-
from commons.data_access_layer.cosmos_db import current_datetime, current_datetime_str
10+
from commons.data_access_layer.cosmos_db import current_datetime, \
11+
current_datetime_str, get_date_range_of_month, get_current_month, \
12+
get_current_year, datetime_str
1113

1214
fake = Faker()
1315

@@ -470,3 +472,44 @@ def test_create_with_valid_uuid_format_should_return_created(client: FlaskClient
470472
assert HTTPStatus.CREATED == response.status_code
471473
repository_container_create_item_mock.assert_called()
472474

475+
476+
@pytest.mark.parametrize(
477+
'url,month,year',
478+
[
479+
('/time-entries?month=4&year=2020', 4, 2020),
480+
('/time-entries?month=4', 4, get_current_year()),
481+
('/time-entries', get_current_month(), get_current_year())
482+
]
483+
)
484+
def test_find_all_is_called_with_generated_dates(client: FlaskClient,
485+
mocker: MockFixture,
486+
valid_header: dict,
487+
tenant_id: str,
488+
owner_id: str,
489+
url: str,
490+
month: int,
491+
year: int):
492+
from time_tracker_api.time_entries.time_entries_namespace import time_entries_dao
493+
repository_find_all_mock = mocker.patch.object(time_entries_dao.repository,
494+
'find_all',
495+
return_value=fake_time_entry)
496+
497+
response = client.get(url,
498+
headers=valid_header,
499+
follow_redirects=True)
500+
501+
start_date, end_date = get_date_range_of_month(year, month)
502+
custom_args = {
503+
'start_date': datetime_str(start_date),
504+
'end_date': datetime_str(end_date)
505+
}
506+
507+
conditions = {
508+
'owner_id': owner_id
509+
}
510+
511+
assert HTTPStatus.OK == response.status_code
512+
assert json.loads(response.data) is not None
513+
repository_find_all_mock.assert_called_once_with(partition_key_value=tenant_id,
514+
conditions=conditions,
515+
custom_args=custom_args)

time_tracker_api/time_entries/time_entries_model.py

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import abc
22
from dataclasses import dataclass, field
3-
from typing import List, Callable, Tuple
4-
from datetime import datetime
3+
from typing import List, Callable
54

65
from azure.cosmos import PartitionKey
76
from flask_restplus._http import HTTPStatus
87

98
from commons.data_access_layer.cosmos_db import CosmosDBDao, CosmosDBRepository, CustomError, current_datetime_str, \
10-
CosmosDBModel
9+
CosmosDBModel, get_date_range_of_month, get_current_year, get_current_month
1110
from commons.data_access_layer.database import CRUDDao
1211
from time_tracker_api.security import current_user_id
1312

@@ -76,31 +75,28 @@ def create_sql_ignore_id_condition(id: str):
7675
return "AND c.id!=@ignore_id"
7776

7877
@staticmethod
79-
def create_sql_date_range_filter(custom_args: dict) -> str:
80-
if 'start_date' and 'end_date' in custom_args:
78+
def create_sql_date_range_filter(date_range: dict) -> str:
79+
if 'start_date' and 'end_date' in date_range:
8180
return """
8281
((c.start_date BETWEEN @start_date AND @end_date) OR
8382
(c.end_date BETWEEN @start_date AND @end_date))
8483
"""
8584
else:
8685
return ''
8786

88-
def find_all(self, partition_key_value: str, conditions: dict, custom_args: dict):
89-
custom_conditions = []
90-
custom_conditions.append(
91-
self.create_sql_date_range_filter(custom_args)
87+
def find_all(self, partition_key_value: str, conditions: dict, date_range: dict):
88+
custom_sql_conditions = []
89+
custom_sql_conditions.append(
90+
self.create_sql_date_range_filter(date_range)
9291
)
9392

94-
custom_params = [
95-
{"name": "@start_date", "value": custom_args.get('start_date')},
96-
{"name": "@end_date", "value": custom_args.get('end_date')},
97-
]
93+
custom_params = self.generate_params(date_range)
9894

9995
return CosmosDBRepository.find_all(
10096
self,
10197
partition_key_value=partition_key_value,
10298
conditions=conditions,
103-
custom_conditions=custom_conditions,
99+
custom_sql_conditions=custom_sql_conditions,
104100
custom_params=custom_params
105101
)
106102

@@ -128,7 +124,7 @@ def find_interception_with_date_range(self, start_date, end_date, owner_id, part
128124
{"name": "@end_date", "value": end_date or current_datetime_str()},
129125
{"name": "@ignore_id", "value": ignore_id},
130126
]
131-
params.extend(self.generate_condition_values(conditions))
127+
params.extend(self.generate_params(conditions))
132128
result = self.container.query_items(
133129
query="""
134130
SELECT * FROM c WHERE ((c.start_date BETWEEN @start_date AND @end_date)
@@ -159,7 +155,7 @@ def find_running(self, partition_key_value: str, owner_id: str, mapper: Callable
159155
visibility_condition=self.create_sql_condition_for_visibility(True),
160156
conditions_clause=self.create_sql_where_conditions(conditions),
161157
),
162-
parameters=self.generate_condition_values(conditions),
158+
parameters=self.generate_params(conditions),
163159
partition_key=partition_key_value,
164160
max_item_count=1)
165161

@@ -187,31 +183,6 @@ def validate_data(self, data):
187183
description="There is another time entry in that date range")
188184

189185

190-
def get_last_day_of_month(year: int, month: int) -> int:
191-
from calendar import monthrange
192-
return monthrange(year=year, month=month)[1]
193-
194-
195-
def get_current_year() -> int:
196-
return datetime.now().year
197-
198-
199-
def get_current_month() -> int:
200-
return datetime.now().month
201-
202-
203-
def get_date_range_of_month(
204-
year: int,
205-
month: int
206-
) -> Tuple[datetime, datetime]:
207-
first_day_of_month = 1
208-
start_date = datetime(year=year, month=month, day=first_day_of_month)
209-
210-
# TODO : fix bound as this would exclude the last day
211-
last_day_of_month = get_last_day_of_month(year=year, month=month)
212-
end_date = datetime(year=year, month=month, day=last_day_of_month)
213-
return start_date, end_date
214-
215186

216187
class TimeEntriesCosmosDBDao(TimeEntriesDao, CosmosDBDao):
217188
def __init__(self, repository):
@@ -242,13 +213,13 @@ def get_all(self, conditions: dict = {}) -> list:
242213

243214
start_date, end_date = get_date_range_of_month(year, month)
244215

245-
custom_args = {
216+
date_range = {
246217
'start_date': start_date.isoformat(),
247-
'end_date': end_date.isoformat()
218+
'end_date': end_date.isoformat(),
248219
}
249220
return self.repository.find_all(partition_key_value=self.partition_key_value,
250221
conditions=conditions,
251-
custom_args=custom_args)
222+
date_range=date_range)
252223

253224
def get(self, id):
254225
return self.repository.find(id,

time_tracker_api/time_entries/time_entries_namespace.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@
111111
# custom attributes filter
112112
attributes_filter.add_argument('month', required=False,
113113
store_missing=False,
114-
help="(Filter) month to filter",
114+
help="(Filter) Month to filter by",
115115
location='args')
116116
attributes_filter.add_argument('year', required=False,
117117
store_missing=False,
118-
help="(Filter) year to filter",
118+
help="(Filter) Year to filter by",
119119
location='args')
120120

121121
@ns.route('')

0 commit comments

Comments
 (0)