Skip to content

Commit b494a75

Browse files
committed
feat: add filter per month and year
1 parent 495190d commit b494a75

File tree

3 files changed

+106
-6
lines changed

3 files changed

+106
-6
lines changed

commons/data_access_layer/cosmos_db.py

Lines changed: 17 additions & 4 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
5+
from typing import Callable, List
66

77
import azure.cosmos.cosmos_client as cosmos_client
88
import azure.cosmos.exceptions as exceptions
@@ -116,6 +116,17 @@ def create_sql_where_conditions(conditions: dict, container_name='c') -> str:
116116
else:
117117
return ""
118118

119+
@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+
)
127+
else:
128+
return ''
129+
119130
@staticmethod
120131
def generate_condition_values(conditions: dict) -> dict:
121132
result = []
@@ -154,8 +165,8 @@ def find(self, id: str, partition_key_value, peeker: 'function' = None,
154165
function_mapper = self.get_mapper_or_dict(mapper)
155166
return function_mapper(self.check_visibility(found_item, visible_only))
156167

157-
def find_all(self, partition_key_value: str, conditions: dict = {}, max_count=None, offset=0,
158-
visible_only=True, mapper: Callable = None):
168+
def find_all(self, partition_key_value: str, conditions: dict = {}, custom_conditions: List[str] = [],
169+
custom_params: dict = {}, max_count=None, offset=0, visible_only=True, mapper: Callable = None):
159170
# TODO Use the tenant_id param and change container alias
160171
max_count = self.get_page_size_or(max_count)
161172
params = [
@@ -164,13 +175,15 @@ def find_all(self, partition_key_value: str, conditions: dict = {}, max_count=No
164175
{"name": "@max_count", "value": max_count},
165176
]
166177
params.extend(self.generate_condition_values(conditions))
178+
params.extend(custom_params)
167179
result = self.container.query_items(query="""
168180
SELECT * FROM c WHERE c.{partition_key_attribute}=@partition_key_value
169-
{conditions_clause} {visibility_condition} {order_clause}
181+
{conditions_clause} {visibility_condition} {custom_conditions_clause} {order_clause}
170182
OFFSET @offset LIMIT @max_count
171183
""".format(partition_key_attribute=self.partition_key_attribute,
172184
visibility_condition=self.create_sql_condition_for_visibility(visible_only),
173185
conditions_clause=self.create_sql_where_conditions(conditions),
186+
custom_conditions_clause=self.create_sql_custom_conditions(custom_conditions),
174187
order_clause=self.create_sql_order_clause()),
175188
parameters=params,
176189
partition_key=partition_key_value,

time_tracker_api/time_entries/time_entries_model.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import abc
22
from dataclasses import dataclass, field
3-
from typing import List, Callable
3+
from typing import List, Callable, Tuple
4+
from datetime import datetime
45

56
from azure.cosmos import PartitionKey
67
from flask_restplus._http import HTTPStatus
@@ -74,6 +75,35 @@ def create_sql_ignore_id_condition(id: str):
7475
else:
7576
return "AND c.id!=@ignore_id"
7677

78+
@staticmethod
79+
def create_sql_date_range_filter(custom_args: dict) -> str:
80+
if 'start_date' and 'end_date' in custom_args:
81+
return """
82+
((c.start_date BETWEEN @start_date AND @end_date) OR
83+
(c.end_date BETWEEN @start_date AND @end_date))
84+
"""
85+
else:
86+
return ''
87+
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)
92+
)
93+
94+
custom_params = [
95+
{"name": "@start_date", "value": custom_args.get('start_date')},
96+
{"name": "@end_date", "value": custom_args.get('end_date')},
97+
]
98+
99+
return CosmosDBRepository.find_all(
100+
self,
101+
partition_key_value=partition_key_value,
102+
conditions=conditions,
103+
custom_conditions=custom_conditions,
104+
custom_params=custom_params
105+
)
106+
77107
def on_create(self, new_item_data: dict):
78108
CosmosDBRepository.on_create(self, new_item_data)
79109

@@ -157,6 +187,32 @@ def validate_data(self, data):
157187
description="There is another time entry in that date range")
158188

159189

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+
215+
160216
class TimeEntriesCosmosDBDao(TimeEntriesDao, CosmosDBDao):
161217
def __init__(self, repository):
162218
CosmosDBDao.__init__(self, repository)
@@ -170,8 +226,29 @@ def check_whether_current_user_owns_item(cls, data: dict):
170226

171227
def get_all(self, conditions: dict = {}) -> list:
172228
conditions.update({"owner_id": self.current_user_id()})
229+
230+
if 'month' and 'year' in conditions:
231+
month = int(conditions.get("month"))
232+
year = int(conditions.get("year"))
233+
conditions.pop('month')
234+
conditions.pop('year')
235+
elif 'month' in conditions:
236+
month = int(conditions.get("month"))
237+
year = get_current_year()
238+
conditions.pop('month')
239+
else:
240+
month = get_current_month()
241+
year = get_current_year()
242+
243+
start_date, end_date = get_date_range_of_month(year, month)
244+
245+
custom_args = {
246+
'start_date': start_date.isoformat(),
247+
'end_date': end_date.isoformat()
248+
}
173249
return self.repository.find_all(partition_key_value=self.partition_key_value,
174-
conditions=conditions)
250+
conditions=conditions,
251+
custom_args=custom_args)
175252

176253
def get(self, id):
177254
return self.repository.find(id,

time_tracker_api/time_entries/time_entries_namespace.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,20 @@
108108
"uri",
109109
])
110110

111+
# custom attributes filter
112+
attributes_filter.add_argument('month', required=False,
113+
store_missing=False,
114+
help="(Filter) month to filter",
115+
location='args')
116+
attributes_filter.add_argument('year', required=False,
117+
store_missing=False,
118+
help="(Filter) year to filter",
119+
location='args')
111120

112121
@ns.route('')
113122
class TimeEntries(Resource):
114123
@ns.doc('list_time_entries')
124+
@ns.expect(attributes_filter)
115125
@ns.marshal_list_with(time_entry)
116126
def get(self):
117127
"""List all time entries"""

0 commit comments

Comments
 (0)