Skip to content

Commit 3c4fb10

Browse files
authored
feat: TT 243 Refactor functions on time entries repository (#298)
* feat: TT-243 Add functions and testing to base query builder * feat: TT-243 Add function and testing to time entries query builder * feat: TT-243 Refactor find_running and find_interception_with_date_range functions * feat: TT-243 Add current datetime if end_date is None * feat: TT-243 Fixing code smells * feat: TT-243 Improve code quality by fixing code smells * feat: TT-243 Refactor code based on PR reviews
1 parent 533756b commit 3c4fb10

File tree

3 files changed

+145
-55
lines changed

3 files changed

+145
-55
lines changed

tests/time_tracker_api/time_entries/time_entries_query_builder_test.py

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@ def test_TimeEntryQueryBuilder_is_subclass_CosmosDBQueryBuilder():
1616

1717

1818
def test_add_sql_date_range_condition_should_update_where_list():
19+
start_date = "2021-03-19T05:07:00.000Z"
20+
end_date = "2021-03-25T10:00:00.000Z"
1921
time_entry_query_builder = (
2022
TimeEntryQueryBuilder().add_sql_date_range_condition(
2123
{
22-
"start_date": "2021-03-19T05:07:00.000Z",
23-
"end_date": "2021-03-25T10:00:00.000Z",
24+
"start_date": start_date,
25+
"end_date": end_date,
2426
}
2527
)
2628
)
2729
expected_params = [
28-
{"name": "@start_date", "value": "2021-03-19T05:07:00.000Z"},
29-
{"name": "@end_date", "value": "2021-03-25T10:00:00.000Z"},
30+
{"name": "@start_date", "value": start_date},
31+
{"name": "@end_date", "value": end_date},
3032
]
3133
assert len(time_entry_query_builder.where_conditions) == 1
3234
assert len(time_entry_query_builder.parameters) == len(expected_params)
@@ -38,8 +40,8 @@ def test_build_with_add_sql_date_range_condition():
3840
TimeEntryQueryBuilder()
3941
.add_sql_date_range_condition(
4042
{
41-
"start_date": "2021-03-19T05:00:00.000Z",
42-
"end_date": "2021-03-20T10:00:00.000Z",
43+
"start_date": "2021-04-19T05:00:00.000Z",
44+
"end_date": "2021-04-20T10:00:00.000Z",
4345
}
4446
)
4547
.build()
@@ -55,3 +57,74 @@ def test_build_with_add_sql_date_range_condition():
5557
assert remove_white_spaces(query) == remove_white_spaces(expected_query)
5658
assert len(time_entry_query_builder.where_conditions) == 1
5759
assert len(time_entry_query_builder.get_parameters()) == 2
60+
61+
62+
def test_add_sql_interception_with_date_range_condition():
63+
start_date = "2021-01-19T05:07:00.000Z"
64+
end_date = "2021-01-25T10:00:00.000Z"
65+
66+
time_entry_query_builder = (
67+
TimeEntryQueryBuilder().add_sql_interception_with_date_range_condition(
68+
start_date, end_date
69+
)
70+
)
71+
72+
expected_params = [
73+
{"name": "@start_date", "value": start_date},
74+
{"name": "@end_date", "value": end_date},
75+
]
76+
77+
assert len(time_entry_query_builder.where_conditions) == 1
78+
assert len(time_entry_query_builder.parameters) == len(expected_params)
79+
assert time_entry_query_builder.parameters == expected_params
80+
81+
82+
def test_build_with_add_sql_interception_with_date_range_condition():
83+
start_date = "2021-02-19T05:07:00.000Z"
84+
end_date = "2021-02-25T10:00:00.000Z"
85+
time_entry_query_builder = (
86+
TimeEntryQueryBuilder()
87+
.add_sql_interception_with_date_range_condition(start_date, end_date)
88+
.build()
89+
)
90+
91+
expected_query = """
92+
SELECT * FROM c
93+
WHERE (((c.start_date BETWEEN @start_date AND @end_date)
94+
OR (c.end_date BETWEEN @start_date AND @end_date))
95+
OR ((@start_date BETWEEN c.start_date AND c.end_date)
96+
OR (@end_date BETWEEN c.start_date AND c.end_date)))
97+
AND c.start_date!= @end_date
98+
AND c.end_date!= @start_date
99+
"""
100+
101+
builder_query = time_entry_query_builder.get_query()
102+
103+
assert remove_white_spaces(builder_query) == remove_white_spaces(
104+
expected_query
105+
)
106+
107+
108+
def test_add_sql_is_running_time_entry_condition_should_update_where_conditions_list():
109+
query_builder = (
110+
TimeEntryQueryBuilder().add_sql_is_running_time_entry_condition()
111+
)
112+
113+
assert len(query_builder.where_conditions) == 1
114+
115+
116+
@pytest.mark.parametrize(
117+
"expected_condition,expected_params",
118+
[("c.id!=@ignore_id", {"name": "@ignore_id", "value": "nomatter"})],
119+
)
120+
def test_add_sql_ignore_id_condition_should_update_where_conditions_list(
121+
expected_condition, expected_params
122+
):
123+
query_builder = TimeEntryQueryBuilder().add_sql_ignore_id_condition(
124+
'nomatter'
125+
)
126+
127+
assert len(query_builder.where_conditions) == 1
128+
assert len(query_builder.parameters) == 1
129+
assert query_builder.where_conditions[0].strip() == expected_condition
130+
assert query_builder.parameters[0] == expected_params

time_tracker_api/time_entries/time_entries_query_builder.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,34 @@ def add_sql_date_range_condition(self, date_range: tuple = None):
2121
]
2222
)
2323
return self
24+
25+
def add_sql_interception_with_date_range_condition(
26+
self, start_date, end_date
27+
):
28+
condition = """
29+
(((c.start_date BETWEEN @start_date AND @end_date)
30+
OR (c.end_date BETWEEN @start_date AND @end_date))
31+
OR ((@start_date BETWEEN c.start_date AND c.end_date)
32+
OR (@end_date BETWEEN c.start_date AND c.end_date)))
33+
AND c.start_date!= @end_date
34+
AND c.end_date!= @start_date
35+
"""
36+
self.where_conditions.append(condition)
37+
self.parameters.extend(
38+
[
39+
{'name': '@start_date', 'value': start_date},
40+
{'name': '@end_date', 'value': end_date},
41+
]
42+
)
43+
return self
44+
45+
def add_sql_is_running_time_entry_condition(self):
46+
condition = "(NOT IS_DEFINED(c.end_date) OR c.end_date = null)"
47+
self.where_conditions.append(condition)
48+
return self
49+
50+
def add_sql_ignore_id_condition(self, id: str = None):
51+
if id:
52+
self.where_conditions.append("c.id!=@ignore_id")
53+
self.parameters.append({'name': '@ignore_id', 'value': id})
54+
return self

time_tracker_api/time_entries/time_entries_repository.py

Lines changed: 35 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,6 @@ def __init__(self):
4242
mapper=TimeEntryCosmosDBModel,
4343
)
4444

45-
@staticmethod
46-
def create_sql_ignore_id_condition(id: str):
47-
if id is None:
48-
return ''
49-
else:
50-
return "AND c.id!=@ignore_id"
51-
5245
def find_all_entries(
5346
self,
5447
event_context: EventContext,
@@ -247,35 +240,25 @@ def find_interception_with_date_range(
247240
"owner_id": owner_id,
248241
"tenant_id": tenant_id,
249242
}
250-
params = [
251-
{"name": "@start_date", "value": start_date},
252-
{"name": "@end_date", "value": end_date or current_datetime_str()},
253-
{"name": "@ignore_id", "value": ignore_id},
254-
]
255-
params.extend(self.generate_params(conditions))
243+
end_date = end_date or current_datetime_str()
244+
245+
query_builder = (
246+
TimeEntryQueryBuilder()
247+
.add_sql_interception_with_date_range_condition(
248+
start_date, end_date
249+
)
250+
.add_sql_where_equal_condition(conditions)
251+
.add_sql_ignore_id_condition(ignore_id)
252+
.add_sql_visibility_condition(visible_only)
253+
.add_sql_order_by_condition('start_date', Order.DESC)
254+
.build()
255+
)
256+
257+
query_str = query_builder.get_query()
258+
params = query_builder.get_parameters()
259+
256260
result = self.container.query_items(
257-
query="""
258-
SELECT * FROM c
259-
WHERE (((c.start_date BETWEEN @start_date AND @end_date)
260-
OR (c.end_date BETWEEN @start_date AND @end_date))
261-
OR ((@start_date BETWEEN c.start_date AND c.end_date)
262-
OR (@end_date BETWEEN c.start_date AND c.end_date)))
263-
AND c.start_date!= @end_date
264-
AND c.end_date!= @start_date
265-
{conditions_clause}
266-
{ignore_id_condition}
267-
{visibility_condition}
268-
{order_clause}
269-
""".format(
270-
ignore_id_condition=self.create_sql_ignore_id_condition(
271-
ignore_id
272-
),
273-
visibility_condition=self.create_sql_condition_for_visibility(
274-
visible_only
275-
),
276-
conditions_clause=self.create_sql_where_conditions(conditions),
277-
order_clause=self.create_sql_order_clause(),
278-
),
261+
query=query_str,
279262
parameters=params,
280263
partition_key=tenant_id,
281264
)
@@ -290,28 +273,31 @@ def find_running(
290273
"owner_id": owner_id,
291274
"tenant_id": tenant_id,
292275
}
276+
277+
query_builder = (
278+
TimeEntryQueryBuilder()
279+
.add_sql_is_running_time_entry_condition()
280+
.add_sql_where_equal_condition(conditions)
281+
.add_sql_visibility_condition(True)
282+
.add_sql_offset_condition(0)
283+
.add_sql_limit_condition(1)
284+
.build()
285+
)
286+
287+
query_str = query_builder.get_query()
288+
params = query_builder.get_parameters()
289+
293290
result = self.container.query_items(
294-
query="""
295-
SELECT * from c
296-
WHERE (NOT IS_DEFINED(c.end_date) OR c.end_date = null)
297-
{conditions_clause}
298-
{visibility_condition}
299-
OFFSET 0 LIMIT 1
300-
""".format(
301-
visibility_condition=self.create_sql_condition_for_visibility(
302-
True
303-
),
304-
conditions_clause=self.create_sql_where_conditions(conditions),
305-
),
306-
parameters=self.generate_params(conditions),
291+
query=query_str,
292+
parameters=params,
307293
partition_key=tenant_id,
308294
max_item_count=1,
309295
)
310296

311297
function_mapper = self.get_mapper_or_dict(mapper)
312298
try:
313299
return function_mapper(next(result))
314-
except StopIteration as no_result:
300+
except StopIteration:
315301
raise CustomError(HTTPStatus.NO_CONTENT)
316302

317303
def validate_data(self, data, event_context: EventContext):

0 commit comments

Comments
 (0)