Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ def test_TimeEntryQueryBuilder_is_subclass_CosmosDBQueryBuilder():


def test_add_sql_date_range_condition_should_update_where_list():
start_date = "2021-03-19T05:07:00.000Z"
end_date = "2021-03-25T10:00:00.000Z"
time_entry_query_builder = (
TimeEntryQueryBuilder().add_sql_date_range_condition(
{
"start_date": "2021-03-19T05:07:00.000Z",
"end_date": "2021-03-25T10:00:00.000Z",
"start_date": start_date,
"end_date": end_date,
}
)
)
expected_params = [
{"name": "@start_date", "value": "2021-03-19T05:07:00.000Z"},
{"name": "@end_date", "value": "2021-03-25T10:00:00.000Z"},
{"name": "@start_date", "value": start_date},
{"name": "@end_date", "value": end_date},
]
assert len(time_entry_query_builder.where_conditions) == 1
assert len(time_entry_query_builder.parameters) == len(expected_params)
Expand All @@ -38,8 +40,8 @@ def test_build_with_add_sql_date_range_condition():
TimeEntryQueryBuilder()
.add_sql_date_range_condition(
{
"start_date": "2021-03-19T05:00:00.000Z",
"end_date": "2021-03-20T10:00:00.000Z",
"start_date": "2021-04-19T05:00:00.000Z",
"end_date": "2021-04-20T10:00:00.000Z",
}
)
.build()
Expand All @@ -55,3 +57,74 @@ def test_build_with_add_sql_date_range_condition():
assert remove_white_spaces(query) == remove_white_spaces(expected_query)
assert len(time_entry_query_builder.where_conditions) == 1
assert len(time_entry_query_builder.get_parameters()) == 2


def test_add_sql_interception_with_date_range_condition():
start_date = "2021-01-19T05:07:00.000Z"
end_date = "2021-01-25T10:00:00.000Z"

time_entry_query_builder = (
TimeEntryQueryBuilder().add_sql_interception_with_date_range_condition(
start_date, end_date
)
)

expected_params = [
{"name": "@start_date", "value": start_date},
{"name": "@end_date", "value": end_date},
]

assert len(time_entry_query_builder.where_conditions) == 1
assert len(time_entry_query_builder.parameters) == len(expected_params)
assert time_entry_query_builder.parameters == expected_params


def test_build_with_add_sql_interception_with_date_range_condition():
start_date = "2021-02-19T05:07:00.000Z"
end_date = "2021-02-25T10:00:00.000Z"
time_entry_query_builder = (
TimeEntryQueryBuilder()
.add_sql_interception_with_date_range_condition(start_date, end_date)
.build()
)

expected_query = """
SELECT * FROM c
WHERE (((c.start_date BETWEEN @start_date AND @end_date)
OR (c.end_date BETWEEN @start_date AND @end_date))
OR ((@start_date BETWEEN c.start_date AND c.end_date)
OR (@end_date BETWEEN c.start_date AND c.end_date)))
AND c.start_date!= @end_date
AND c.end_date!= @start_date
"""

builder_query = time_entry_query_builder.get_query()

assert remove_white_spaces(builder_query) == remove_white_spaces(
expected_query
)


def test_add_sql_is_running_time_entry_condition_should_update_where_conditions_list():
query_builder = (
TimeEntryQueryBuilder().add_sql_is_running_time_entry_condition()
)

assert len(query_builder.where_conditions) == 1


@pytest.mark.parametrize(
"expected_condition,expected_params",
[("c.id!=@ignore_id", {"name": "@ignore_id", "value": "nomatter"})],
)
def test_add_sql_ignore_id_condition_should_update_where_conditions_list(
expected_condition, expected_params
):
query_builder = TimeEntryQueryBuilder().add_sql_ignore_id_condition(
'nomatter'
)

assert len(query_builder.where_conditions) == 1
assert len(query_builder.parameters) == 1
assert query_builder.where_conditions[0].strip() == expected_condition
assert query_builder.parameters[0] == expected_params
31 changes: 31 additions & 0 deletions time_tracker_api/time_entries/time_entries_query_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,34 @@ def add_sql_date_range_condition(self, date_range: tuple = None):
]
)
return self

def add_sql_interception_with_date_range_condition(
self, start_date, end_date
):
condition = """
(((c.start_date BETWEEN @start_date AND @end_date)
OR (c.end_date BETWEEN @start_date AND @end_date))
OR ((@start_date BETWEEN c.start_date AND c.end_date)
OR (@end_date BETWEEN c.start_date AND c.end_date)))
AND c.start_date!= @end_date
AND c.end_date!= @start_date
"""
self.where_conditions.append(condition)
self.parameters.extend(
[
{'name': '@start_date', 'value': start_date},
{'name': '@end_date', 'value': end_date},
]
)
return self

def add_sql_is_running_time_entry_condition(self):
condition = "(NOT IS_DEFINED(c.end_date) OR c.end_date = null)"
self.where_conditions.append(condition)
return self

def add_sql_ignore_id_condition(self, id: str = None):
if id:
self.where_conditions.append("c.id!=@ignore_id")
self.parameters.append({'name': '@ignore_id', 'value': id})
return self
84 changes: 35 additions & 49 deletions time_tracker_api/time_entries/time_entries_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ def __init__(self):
mapper=TimeEntryCosmosDBModel,
)

@staticmethod
def create_sql_ignore_id_condition(id: str):
if id is None:
return ''
else:
return "AND c.id!=@ignore_id"

def find_all_entries(
self,
event_context: EventContext,
Expand Down Expand Up @@ -247,35 +240,25 @@ def find_interception_with_date_range(
"owner_id": owner_id,
"tenant_id": tenant_id,
}
params = [
{"name": "@start_date", "value": start_date},
{"name": "@end_date", "value": end_date or current_datetime_str()},
{"name": "@ignore_id", "value": ignore_id},
]
params.extend(self.generate_params(conditions))
end_date = end_date or current_datetime_str()

query_builder = (
TimeEntryQueryBuilder()
.add_sql_interception_with_date_range_condition(
start_date, end_date
)
.add_sql_where_equal_condition(conditions)
.add_sql_ignore_id_condition(ignore_id)
.add_sql_visibility_condition(visible_only)
.add_sql_order_by_condition('start_date', Order.DESC)
.build()
)

query_str = query_builder.get_query()
params = query_builder.get_parameters()

result = self.container.query_items(
query="""
SELECT * FROM c
WHERE (((c.start_date BETWEEN @start_date AND @end_date)
OR (c.end_date BETWEEN @start_date AND @end_date))
OR ((@start_date BETWEEN c.start_date AND c.end_date)
OR (@end_date BETWEEN c.start_date AND c.end_date)))
AND c.start_date!= @end_date
AND c.end_date!= @start_date
{conditions_clause}
{ignore_id_condition}
{visibility_condition}
{order_clause}
""".format(
ignore_id_condition=self.create_sql_ignore_id_condition(
ignore_id
),
visibility_condition=self.create_sql_condition_for_visibility(
visible_only
),
conditions_clause=self.create_sql_where_conditions(conditions),
order_clause=self.create_sql_order_clause(),
),
query=query_str,
parameters=params,
partition_key=tenant_id,
)
Expand All @@ -290,28 +273,31 @@ def find_running(
"owner_id": owner_id,
"tenant_id": tenant_id,
}

query_builder = (
TimeEntryQueryBuilder()
.add_sql_is_running_time_entry_condition()
.add_sql_where_equal_condition(conditions)
.add_sql_visibility_condition(True)
.add_sql_offset_condition(0)
.add_sql_limit_condition(1)
.build()
)

query_str = query_builder.get_query()
params = query_builder.get_parameters()

result = self.container.query_items(
query="""
SELECT * from c
WHERE (NOT IS_DEFINED(c.end_date) OR c.end_date = null)
{conditions_clause}
{visibility_condition}
OFFSET 0 LIMIT 1
""".format(
visibility_condition=self.create_sql_condition_for_visibility(
True
),
conditions_clause=self.create_sql_where_conditions(conditions),
),
parameters=self.generate_params(conditions),
query=query_str,
parameters=params,
partition_key=tenant_id,
max_item_count=1,
)

function_mapper = self.get_mapper_or_dict(mapper)
try:
return function_mapper(next(result))
except StopIteration as no_result:
except StopIteration:
raise CustomError(HTTPStatus.NO_CONTENT)

def validate_data(self, data, event_context: EventContext):
Expand Down