Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add subquery tests for EmbeddedModelField #226

Merged
merged 2 commits into from
Jan 24, 2025

Conversation

WaVEV
Copy link
Collaborator

@WaVEV WaVEV commented Jan 18, 2025

No description provided.

@WaVEV WaVEV requested a review from timgraham January 18, 2025 05:23
@WaVEV WaVEV force-pushed the EMF-subquery-tests branch from 27ec33c to 77d6286 Compare January 18, 2025 21:20


class SubqueryExistsTest(TestCase):
def setUp(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use setUpTestData?

@@ -123,3 +129,62 @@ class MyModel(models.Model):
self.assertEqual(
msg, "Embedded models cannot have relational fields (Target.key is a ForeignKey)."
)


class SubqueryExistsTest(TestCase):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests

self.assertEqual(queryset.count(), 3)
self.assertQuerySetEqual(queryset, ["Book B", "Book C", "Book D"], lambda book: book.name)

def test_range_query(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why in this class? Is it because the count() does an aggregation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test could be put in a better place. Will move

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should be in a different commit with this one

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would need to be rewritten because it relies on this class's test data, so I didn't include it there. Probably range could be tested with Holder in QueryingTests, but I'm not sure it's a pressing need considering all the other lookups that aren't explicitly tested.

Copy link
Collaborator Author

@WaVEV WaVEV Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will rewrite it. I think is a good to have, we also need to test if the range is covered.

author__name=OuterRef("name"), author__address__city="Boston"
)
queryset = Author.objects.filter(Exists(subquery))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please omit the blank lines.


def test_in_subquery(self):
subquery = Author.objects.filter(age__gt=35).values("name")
queryset = Book.objects.filter(author__name__in=Subquery(subquery)).order_by("name")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I tested, the Subquery wrapping of subquery is unnecessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh yes, don't remember why i added that

address2 = Address.objects.create(city="Boston", state="MA", zip_code=20002)
author1 = Author.objects.create(name="Alice", age=30, address=address1)
author2 = Author.objects.create(name="Bob", age=40, address=address2)
book1 = Book.objects.create(name="Book A", author=author1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to title it "Book 1" rather than switching between letters and numbers.

class SubqueryExistsTest(TestCase):
def setUp(self):
# Create test data
address1 = Address.objects.create(city="New York", state="NY", zip_code=10001)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedded models should be saved to the database in their own collection (i.e. no create()). #216 will prohibit it.

author__name=OuterRef("author__name"), author__address__city="Boston"
)
queryset = Book.objects.filter(Exists(subquery)).order_by("name")
self.assertEqual(queryset.count(), 3)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the .count() to check the length or to check that count works correctly? It's just that assertQuerySetEqual will give a more helpful message about any extra or missing elements.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, will remove


class SubqueryExistsTests(TestCase):
def setUpTestData(self):
# Create test data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment not needed

library2 = Library.objects.create(
name="Community Library", location="Suburbs", best_seller="Book 1"
)
# Add books to libraries
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment not needed

self.assertEqual(queryset.count(), 3)
self.assertQuerySetEqual(queryset, ["Book B", "Book C", "Book D"], lambda book: book.name)

def test_range_query(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would need to be rewritten because it relies on this class's test data, so I didn't include it there. Probably range could be tested with Holder in QueryingTests, but I'm not sure it's a pressing need considering all the other lookups that aren't explicitly tested.

@timgraham timgraham changed the title EMF add subqueries tests add subquery tests for EmbeddedModelField Jan 23, 2025
@WaVEV WaVEV force-pushed the EMF-subquery-tests branch from 10dbdc3 to 6f383ee Compare January 23, 2025 04:50
def test_range_query(self):
sorted_obj = sorted(self.objs, key=lambda x: x.data.auto_now)
queryset = Holder.objects.filter(
data__auto_now__range=(sorted_obj[2].data.auto_now, sorted_obj[-1].data.auto_now)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to do range on data__integer? To me, this is similar to the other lookup tests (e.g. group under test_gte) and those look so much simpler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None, I want to try if the dates works fine. I know that is not the place to do that, but is not wrong.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the test worked locally and failed on CI, I'd guess it's due to milliseconds (fixable with truncate_ms() perhaps). I think we wouldn't have these truncate_ms() issues if we had a way to truncate milliseconds at https://github.com/django/django/blob/f133285a9a7f3647fd55abc2e57b8a9a2c11ac94/django/db/models/fields/__init__.py#L1649-L1655. It might be possible with a change in Django.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap, is a flaky test. give that sometimes two elements has the same time. (due to precision). Will fix it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

range in integers in order to keep the test simple

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is a one-liner similar to the other lookup tests insufficient? What's the important part of the test? That range works? That ordering works? That count() works? Everything together? Just trying to understand your thinking about why you made it part of this PR. Not sure if I got the indices right, but I had something like this in mind:

self.assertCountEqual(Holder.objects.filter(data__integer__range=(2, 5)), self.objs[2:5])

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 the order by is just to comparing results. It has nothing more to do with the test. So It is good to have one liner test

@timgraham timgraham merged commit 9b4083f into mongodb-labs:main Jan 24, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants