Skip to content

Commit

Permalink
empty queryset handling
Browse files Browse the repository at this point in the history
  • Loading branch information
iNishant committed Jul 4, 2024
1 parent 8c0fc90 commit 545cf5d
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 15 deletions.
25 changes: 20 additions & 5 deletions django_querysets_single_query_fetch/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def __init__(self, queryset: QuerySet) -> None:

QuerysetWrapperType = Union[QuerySet, QuerysetCountWrapper, QuerysetGetOrNoneWrapper]

RESULT_PLACEHOLDER = object()


class QuerysetsSingleQueryFetch:
"""
Expand Down Expand Up @@ -379,6 +381,17 @@ def _convert_raw_results_to_final_queryset_results(

return queryset_results

def _get_empty_queryset_value(self, queryset: QuerysetWrapperType) -> Any:
if isinstance(queryset, QuerysetCountWrapper):
empty_sql_val = 0
elif isinstance(queryset, QuerysetGetOrNoneWrapper):
empty_sql_val = None
else:
# normal queryset
empty_sql_val = []

return empty_sql_val

def execute(self) -> list[list[Any]]:
django_sqls_for_querysets = [
self._get_django_sql_for_queryset(queryset=queryset)
Expand All @@ -387,12 +400,14 @@ def execute(self) -> list[list[Any]]:

final_result_list: List[Any] = []

for queryset_sql in django_sqls_for_querysets:
for queryset_sql, queryset in zip(django_sqls_for_querysets, self.querysets):
if not queryset_sql:
final_result_list.append([])
final_result_list.append(
self._get_empty_queryset_value(queryset=queryset)
)
else:
final_result_list.append(
None
RESULT_PLACEHOLDER
) # will be replaced by actual result below

non_empty_django_sqls_for_querysets = [
Expand All @@ -415,8 +430,8 @@ def execute(self) -> list[list[Any]]:
final_result = []
index = 0
for queryset, result in zip(self.querysets, final_result_list):
if result is not None:
# empty case EmptyResultSet
if result is not RESULT_PLACEHOLDER:
# empty sql case
final_result.append(result)
continue
final_result.append(
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setuptools.setup(
name="django_querysets_single_query_fetch",
version="0.0.9",
version="0.0.10",
description="Execute multiple Django querysets in a single SQL query",
long_description="Utility which executes multiple Django querysets over a single network/query call and returns results which would have been returned in normal evaluation of querysets",
author="Nishant Singh",
Expand Down
22 changes: 13 additions & 9 deletions testapp/tests/test_count_wrapper_for_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,7 @@ def setUp(self) -> None:
StoreProduct, store=self.store, category=self.category, selling_price=100.33
)

def test_fetch_count(self):
"""
- test fetch count works in single query
_ test fetch count works with filter querysets
_ test fetch count works with other querysets
"""
# test fetch count works in single query
def test_works_in_simple_case(self):
count_queryset = StoreProduct.objects.filter()
with self.assertNumQueries(1):
results = QuerysetsSingleQueryFetch(
Expand All @@ -41,7 +35,7 @@ def test_fetch_count(self):
self.assertEqual(len(results), 1)
self.assertEqual(results[0], count_queryset.count())

# test fetch count works with filter querysets
def test_works_with_filtered_queryset(self):
count_filter_queryset = StoreProduct.objects.filter(id=self.product_1.id)
with self.assertNumQueries(1):
results = QuerysetsSingleQueryFetch(
Expand All @@ -52,7 +46,7 @@ def test_fetch_count(self):
self.assertEqual(len(results), 1)
self.assertEqual(results[0], count_filter_queryset.count())

# test fetch count works with other querysets
def test_works_with_other_querysets(self):
count_queryset = StoreProduct.objects.filter()
count_filter_queryset = StoreProduct.objects.filter(id=self.product_1.id)
queryset = StoreProduct.objects.filter()
Expand All @@ -68,3 +62,13 @@ def test_fetch_count(self):
self.assertEqual(results[0], count_queryset.count())
self.assertEqual(results[1], count_filter_queryset.count())
self.assertEqual(results[2], list(queryset))

def test_count_is_returned_as_zero_for_empty_queryset(self):
with self.assertNumQueries(0):
results = QuerysetsSingleQueryFetch(
querysets=[
QuerysetCountWrapper(StoreProduct.objects.none()),
]
).execute()
self.assertEqual(len(results), 1)
self.assertEqual(results[0], 0)
10 changes: 10 additions & 0 deletions testapp/tests/test_get_or_none_wrapper_for_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,13 @@ def test_get_or_none_wrapper_with_multiple_rows_matching(self):
self.assertTrue(
(product.id == self.product_1.id) or (product.id == self.product_2.id)
)

def test_get_or_none_wrapper_with_empty_queryset(self):
with self.assertNumQueries(0):
results = QuerysetsSingleQueryFetch(
querysets=[
QuerysetGetOrNoneWrapper(StoreProduct.objects.none()),
]
).execute()
self.assertEqual(len(results), 1)
self.assertIsNone(results[0])

0 comments on commit 545cf5d

Please sign in to comment.