Skip to content

Commit 7faa022

Browse files
kellycastrofdependabot[bot]scastillo-jpAngeluz-07
authored
Tt 185 find all method in time entries (#270)
* refactor: TT-185 create SQLBuilder, TimeEntryQueryBuilder and find_all_v2 method in time entries repository * test: TT-185 query_builder tests * test: TT-185 add test methods for TimeEntryQueryBuilder and new function in repository * build: TT-199 build(deps): bump jinja2 in /requirements/time_tracker_api (#268) Bumps [jinja2](https://github.com/pallets/jinja) from 2.11.1 to 2.11.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/master/CHANGES.rst) - [Commits](pallets/jinja@2.11.1...2.11.3) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sandro Castillo <[email protected]> * refactor: TT-185 create SQLBuilder, TimeEntryQueryBuilder and find_all_v2 method in time entries repository * test: TT-185 query_builder tests * test: TT-185 add test methods for TimeEntryQueryBuilder and new function in repository * refactor: TT-185 rename get_string_without_empty_spaces to remove_white_spaces * refactor: TT-185 add time_entries_id in condition * refactor: TT-185 delete isintance validation * refactor: TT-185 improve function remove_white_spaces * refactor: TT-185 change column to columns * refactor: TT-185 add more scenarios to test_add_sql_in_condition_should_update_where_list * refactor: TT-185 add more scenarios to test__build_where_should_return_concatenated_conditions * refactor: TT-185 improve test_TimeEntryQueryBuilder_is_subclass_CosmosDBQueryBuilder * refactor: TT-185 rename args in TimeEntriesRepository * refactor: TT-185 change the scenarios in test_add_sql_date_range_condition_should_update_where_list Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sandro Castillo <[email protected]> Co-authored-by: roberto <[email protected]>
1 parent 7914fdf commit 7faa022

File tree

8 files changed

+527
-8
lines changed

8 files changed

+527
-8
lines changed

tests/time_tracker_api/time_entries/time_entries_model_test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
)
99
from time_tracker_api.time_entries.time_entries_repository import (
1010
TimeEntryCosmosDBRepository,
11+
TimeEntryCosmosDBModel,
1112
)
1213

1314

@@ -266,3 +267,46 @@ def test_updated_item_without_deleted_key_should_call_validate_data(
266267
time_entry_repository.on_update({}, event_context)
267268
on_update_mock.assert_called_once()
268269
time_entry_repository.validate_data.assert_called_once()
270+
271+
272+
@patch(
273+
'time_tracker_api.time_entries.time_entries_repository.TimeEntryCosmosDBRepository.find_partition_key_value'
274+
)
275+
@patch(
276+
'time_tracker_api.time_entries.time_entries_repository.TimeEntryCosmosDBRepository.get_page_size_or'
277+
)
278+
def test_find_all_v2(
279+
get_page_size_or_mock,
280+
find_partition_key_value_mock,
281+
event_context: EventContext,
282+
time_entry_repository: TimeEntryCosmosDBRepository,
283+
):
284+
expected_item = {
285+
'id': 'id',
286+
'start_date': '2021-03-22T10:00:00.000Z',
287+
'end_date': "2021-03-22T11:00:00.000Z",
288+
'description': 'do some testing',
289+
'tenant_id': 'tenant_id',
290+
'project_id': 'project_id',
291+
'activity_id': 'activity_id',
292+
'technologies': ['python'],
293+
}
294+
query_items_mock = Mock(return_value=[expected_item])
295+
time_entry_repository.container = Mock()
296+
time_entry_repository.container.query_items = query_items_mock
297+
298+
result = time_entry_repository.find_all_v2(
299+
event_context,
300+
['owner_id'],
301+
{
302+
'start_date': "2021-03-22T10:00:00.000Z",
303+
'end_date': "2021-03-22T11:00:00.000Z",
304+
},
305+
)
306+
307+
find_partition_key_value_mock.assert_called_once()
308+
get_page_size_or_mock.assert_called_once()
309+
assert len(result) == 1
310+
time_entry = result[0]
311+
assert isinstance(time_entry, TimeEntryCosmosDBModel)
312+
assert time_entry.__dict__ == expected_item
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import pytest
2+
from utils.query_builder import CosmosDBQueryBuilder
3+
from time_tracker_api.time_entries.time_entries_query_builder import (
4+
TimeEntryQueryBuilder,
5+
)
6+
from utils.repository import remove_white_spaces
7+
8+
9+
def test_TimeEntryQueryBuilder_is_subclass_CosmosDBQueryBuilder():
10+
query_builder = CosmosDBQueryBuilder()
11+
time_entries_query_builder = TimeEntryQueryBuilder()
12+
13+
assert issubclass(
14+
time_entries_query_builder.__class__, query_builder.__class__
15+
)
16+
17+
18+
def test_add_sql_date_range_condition_should_update_where_list():
19+
time_entry_query_builder = (
20+
TimeEntryQueryBuilder().add_sql_date_range_condition(
21+
("2021-03-19T05:07:00.000Z", "2021-03-25T10:00:00.000Z")
22+
)
23+
)
24+
expected_params = [
25+
{"name": "@start_date", "value": "2021-03-19T05:07:00.000Z"},
26+
{"name": "@end_date", "value": "2021-03-25T10:00:00.000Z"},
27+
]
28+
assert len(time_entry_query_builder.where_conditions) == 1
29+
assert len(time_entry_query_builder.parameters) == len(expected_params)
30+
assert time_entry_query_builder.get_parameters() == expected_params
31+
32+
33+
def test_build_with_add_sql_date_range_condition():
34+
time_entry_query_builder = (
35+
TimeEntryQueryBuilder()
36+
.add_sql_date_range_condition(
37+
("2021-03-19T05:00:00.000Z", "2021-03-20T10:00:00.000Z")
38+
)
39+
.build()
40+
)
41+
42+
expected_query = """
43+
SELECT * FROM c
44+
WHERE ((c.start_date BETWEEN @start_date AND @end_date) OR
45+
(c.end_date BETWEEN @start_date AND @end_date))
46+
"""
47+
query = time_entry_query_builder.get_query()
48+
49+
assert remove_white_spaces(query) == remove_white_spaces(expected_query)
50+
assert len(time_entry_query_builder.where_conditions) == 1
51+
assert len(time_entry_query_builder.get_parameters()) == 2

tests/utils/query_builder_test.py

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
from unittest.mock import patch
2+
from utils.query_builder import CosmosDBQueryBuilder
3+
from utils.repository import remove_white_spaces
4+
import pytest
5+
6+
7+
@pytest.mark.parametrize(
8+
"condition_list, expected_select_condition",
9+
[
10+
(None, ["*"]),
11+
([], ["*"]),
12+
(["*"], ["*"]),
13+
(["c.id"], ["c.id"]),
14+
(["c.id", "c.name"], ["c.id", "c.name"]),
15+
],
16+
)
17+
def test_add_select_conditions_should_update_select_list(
18+
condition_list, expected_select_condition
19+
):
20+
query_builder = CosmosDBQueryBuilder().add_select_conditions(
21+
condition_list
22+
)
23+
24+
assert len(query_builder.select_conditions) == len(
25+
expected_select_condition
26+
)
27+
assert query_builder.select_conditions == expected_select_condition
28+
29+
30+
@pytest.mark.parametrize(
31+
"attribute,ids_list,expected_where_condition_list",
32+
[
33+
("id", [], []),
34+
(None, None, []),
35+
("id", None, []),
36+
(None, ["id"], []),
37+
("id", ["id"], ["c.id IN ('id')"]),
38+
("id", ["id1", "id2"], ["c.id IN ('id1', 'id2')"]),
39+
("owner_id", ["id1", "id2"], ["c.owner_id IN ('id1', 'id2')"]),
40+
("customer_id", ["id1", "id2"], ["c.customer_id IN ('id1', 'id2')"]),
41+
],
42+
)
43+
def test_add_sql_in_condition_should_update_where_list(
44+
attribute, ids_list, expected_where_condition_list,
45+
):
46+
query_builder = CosmosDBQueryBuilder().add_sql_in_condition(
47+
attribute, ids_list
48+
)
49+
50+
assert len(query_builder.where_conditions) == len(
51+
expected_where_condition_list
52+
)
53+
assert query_builder.where_conditions == expected_where_condition_list
54+
55+
56+
@pytest.mark.parametrize(
57+
"data,expected_where_list,expected_params",
58+
[
59+
({}, [], []),
60+
({'id': 1}, ["c.id = @id"], [{'name': "@id", 'value': 1}]),
61+
(
62+
{'id': 1, 'name': 'test'},
63+
["c.id = @id", "c.name = @name"],
64+
[{'name': "@id", 'value': 1}, {'name': "@name", 'value': 'test'}],
65+
),
66+
],
67+
)
68+
def test_add_sql_where_equal_condition_should_update_where_params_list(
69+
data, expected_where_list, expected_params,
70+
):
71+
query_builder = CosmosDBQueryBuilder().add_sql_where_equal_condition(data)
72+
73+
assert len(query_builder.where_conditions) == len(data)
74+
assert query_builder.where_conditions == expected_where_list
75+
76+
assert len(query_builder.parameters) == len(expected_params)
77+
assert query_builder.parameters == expected_params
78+
79+
80+
def test_add_sql_where_equal_condition_with_None_should_not_update_lists():
81+
query_builder = CosmosDBQueryBuilder().add_sql_where_equal_condition(None)
82+
83+
assert len(query_builder.where_conditions) == 0
84+
assert query_builder.where_conditions == []
85+
assert len(query_builder.parameters) == 0
86+
assert query_builder.parameters == []
87+
88+
89+
@pytest.mark.parametrize(
90+
"visibility_bool,expected_where_list",
91+
[(True, ['NOT IS_DEFINED(c.deleted)']), (False, [])],
92+
)
93+
def test_add_sql_visibility_condition(
94+
visibility_bool, expected_where_list,
95+
):
96+
query_builder = CosmosDBQueryBuilder().add_sql_visibility_condition(
97+
visibility_bool
98+
)
99+
100+
assert len(query_builder.where_conditions) == len(expected_where_list)
101+
assert query_builder.where_conditions == expected_where_list
102+
103+
104+
@pytest.mark.parametrize(
105+
"limit_value,expected_limit", [(1, 1), (10, 10), (None, None),],
106+
)
107+
def test_add_sql_limit_condition(limit_value, expected_limit):
108+
query_builder = CosmosDBQueryBuilder().add_sql_limit_condition(limit_value)
109+
110+
assert query_builder.limit == expected_limit
111+
112+
113+
@pytest.mark.parametrize(
114+
"offset_value,expected_offset", [(1, 1), (10, 10), (None, None),],
115+
)
116+
def test_add_sql_offset_condition(
117+
offset_value, expected_offset,
118+
):
119+
query_builder = CosmosDBQueryBuilder().add_sql_offset_condition(
120+
offset_value
121+
)
122+
123+
assert query_builder.offset == expected_offset
124+
125+
126+
@pytest.mark.parametrize(
127+
"select_conditions,expected_condition",
128+
[([], "*"), (["c.id"], "c.id"), (["c.id", "c.name"], "c.id,c.name"),],
129+
)
130+
def test__build_select_return_fields_in_select_list(
131+
select_conditions, expected_condition,
132+
):
133+
query_builder = CosmosDBQueryBuilder().add_select_conditions(
134+
select_conditions
135+
)
136+
137+
result = query_builder._CosmosDBQueryBuilder__build_select()
138+
assert result == expected_condition
139+
140+
141+
@pytest.mark.parametrize(
142+
"fields,expected_condition",
143+
[
144+
(None, ""),
145+
({}, ""),
146+
({"id": 1}, "WHERE c.id = @id"),
147+
({"id": 1, "name": "test"}, "WHERE c.id = @id AND c.name = @name"),
148+
],
149+
)
150+
def test__build_where_should_return_concatenated_conditions(
151+
fields, expected_condition,
152+
):
153+
query_builder = CosmosDBQueryBuilder().add_sql_where_equal_condition(
154+
fields
155+
)
156+
157+
result = query_builder._CosmosDBQueryBuilder__build_where()
158+
159+
assert result == expected_condition
160+
161+
162+
@pytest.mark.parametrize(
163+
"offset,expected_condition,expected_params",
164+
[(1, "OFFSET @offset", [{'name': '@offset', 'value': 1}]), (None, "", [])],
165+
)
166+
def test__build_offset(
167+
offset, expected_condition, expected_params,
168+
):
169+
query_builder = CosmosDBQueryBuilder().add_sql_offset_condition(offset)
170+
171+
result = query_builder._CosmosDBQueryBuilder__build_offset()
172+
assert result == expected_condition
173+
assert len(query_builder.parameters) == len(expected_params)
174+
assert query_builder.get_parameters() == expected_params
175+
176+
177+
@pytest.mark.parametrize(
178+
"limit,expected_condition,expected_params",
179+
[(1, "LIMIT @limit", [{'name': '@limit', 'value': 1}]), (None, "", [])],
180+
)
181+
def test__build_limit(
182+
limit, expected_condition, expected_params,
183+
):
184+
query_builder = CosmosDBQueryBuilder().add_sql_limit_condition(limit)
185+
186+
result = query_builder._CosmosDBQueryBuilder__build_limit()
187+
assert result == expected_condition
188+
assert len(query_builder.parameters) == len(expected_params)
189+
assert query_builder.get_parameters() == expected_params
190+
191+
192+
def test_build_with_all_calls_return_query_with_all_conditions():
193+
query_builder = (
194+
CosmosDBQueryBuilder()
195+
.add_select_conditions(["c.description"])
196+
.add_sql_in_condition("id", ["id1", "id2"])
197+
.add_sql_where_equal_condition({'name': 'test'})
198+
.add_sql_offset_condition(2)
199+
.add_sql_limit_condition(10)
200+
.add_sql_visibility_condition(True)
201+
.build()
202+
)
203+
query = query_builder.get_query()
204+
expected_query = """
205+
SELECT c.description FROM c
206+
WHERE c.id IN ('id1', 'id2') AND c.name = @name AND NOT IS_DEFINED(c.deleted)
207+
OFFSET @offset
208+
LIMIT @limit
209+
"""
210+
211+
assert remove_white_spaces(query) == remove_white_spaces(expected_query)
212+
assert len(query_builder.get_parameters()) > 0
213+
assert len(query_builder.where_conditions) > 0
214+
assert len(query_builder.select_conditions) > 0
215+
216+
217+
def test_build_with_empty_and_None_attributes_return_query_select_all():
218+
219+
query_builder = (
220+
CosmosDBQueryBuilder()
221+
.add_select_conditions()
222+
.add_sql_in_condition()
223+
.add_sql_where_equal_condition()
224+
.add_sql_limit_condition(None)
225+
.add_sql_offset_condition(None)
226+
.build()
227+
)
228+
229+
query = query_builder.get_query()
230+
expected_query = """SELECT * FROM c"""
231+
232+
query = remove_white_spaces(query)
233+
expected_query = remove_white_spaces(expected_query)
234+
235+
assert query == expected_query
236+
assert len(query_builder.get_parameters()) == 0
237+
assert len(query_builder.where_conditions) == 0

tests/utils/repository_test.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
from unittest.mock import patch
2-
from utils.repository import convert_list_to_tuple_string, create_sql_in_condition
2+
from utils.repository import (
3+
convert_list_to_tuple_string,
4+
create_sql_in_condition,
5+
remove_white_spaces,
6+
)
37
import pytest
48

59

@@ -41,10 +45,18 @@ def test_convert_list_to_tuple_string_should_success(
4145
[
4246
("customer_id", ["id1"], "c.customer_id IN ('id1')"),
4347
("customer_id", ["id1", "id2"], "c.customer_id IN ('id1', 'id2')"),
44-
("customer_id", ["id1", "id2", "id3", "id4"], "c.customer_id IN ('id1', 'id2', 'id3', 'id4')"),
48+
(
49+
"customer_id",
50+
["id1", "id2", "id3", "id4"],
51+
"c.customer_id IN ('id1', 'id2', 'id3', 'id4')",
52+
),
4553
("id", ["id1"], "c.id IN ('id1')"),
4654
("id", ["id1", "id4"], "c.id IN ('id1', 'id4')"),
47-
("id", ["id1", "id2", "id3", "id4"], "c.id IN ('id1', 'id2', 'id3', 'id4')"),
55+
(
56+
"id",
57+
["id1", "id2", "id3", "id4"],
58+
"c.id IN ('id1', 'id2', 'id3', 'id4')",
59+
),
4860
],
4961
)
5062
def test_create_sql_in_condition(
@@ -53,4 +65,17 @@ def test_create_sql_in_condition(
5365
expected_result,
5466
):
5567
result = create_sql_in_condition(field, values)
56-
assert expected_result == result
68+
assert expected_result == result
69+
70+
71+
@pytest.mark.parametrize(
72+
"string,expected_string",
73+
[
74+
(" text with \t tab", "text with tab"),
75+
(" text with \n new line", "text with new line"),
76+
(""" SELECT * from c """, "SELECT * from c"),
77+
],
78+
)
79+
def test_remove_white_spaces(string, expected_string):
80+
string = remove_white_spaces(string)
81+
assert string == expected_string

0 commit comments

Comments
 (0)