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

Annotated Fields in Case-When #1748

Merged
merged 2 commits into from
Oct 26, 2024

Conversation

henadzit
Copy link
Contributor

@henadzit henadzit commented Oct 24, 2024

Description

This PR:

  • Enables use of annotations in Case-When, e.g.
IntFields.all()\
  .annotate(intnum_plus_1=F("intnum") + 1)\
  .annotate(bigger_than_10=Case(When(Q(intnum_plus_1__gte=10), then=True), default=False))

Motivation and Context

Django lets you use annotations in Case-When, so it would be nice to have it too.

ResolveContext simplifies the code by incapsulating all the information required for resolving expressions, i.e. the model, the table, annotations and custom filters as opposed to the old way of assigning _annotations and _custom_filters to expressions. I'm planning on using it to resolve F expressions, for instance, to allow referring to related models in F (related issue).

How Has This Been Tested?

  • Added tests
  • The following snippet can be used to compare the behavior prior and after the changes
import logging
import sys

from tortoise import Tortoise, fields, run_async
from tortoise.models import Model
from tortoise.expressions import F, Q, Case, When

fmt = logging.Formatter(
    fmt="%(asctime)s - %(name)s:%(lineno)d - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)
sh = logging.StreamHandler(sys.stdout)
sh.setLevel(logging.DEBUG)
sh.setFormatter(fmt)

logger_tortoise = logging.getLogger("tortoise")
logger_tortoise.setLevel(logging.DEBUG)
logger_tortoise.addHandler(sh)


class User(Model):
    value = fields.IntField()


async def main():
    # Initializing Tortoise and creating the schema

    await Tortoise.init(  # type: ignore
        db_url="sqlite://:memory:",
        modules={"models": ["__main__"]},
    )
    await Tortoise.generate_schemas()

    await User.create(value=1)
    await User.create(value=2)

    queryset = User.all()
    queryset = queryset.annotate(
        value2=F("value") + 1,
    )
    queryset = queryset.annotate(
        ignore_priority=Case(
            When(Q(value2=2), then=True),
            default=False,
        ),
    )
    res = await queryset
    for user in res:
        print(user.value, user.value2, user.ignore_priority)


run_async(main())

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added the changelog accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

* Pass custom_filters to expressions
* This allows to refer to annotations in Case-When
@henadzit henadzit force-pushed the feat/annotation-in-case-when branch from 7e5ce4f to 0fa73d8 Compare October 24, 2024 15:17
@@ -293,7 +316,6 @@ class QuerySet(AwaitableQuery[MODEL]):
"_q_objects",
"_distinct",
"_having",
"_custom_filters",
Copy link
Contributor Author

@henadzit henadzit Oct 24, 2024

Choose a reason for hiding this comment

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

I'm having a hard time to understand why _custom_filters is changed to custom_filters in QuerySet subclasses (same with force_indexes, annotations, etc.). I would love to know that!

Copy link
Member

Choose a reason for hiding this comment

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

Honestly - I don't remember :)

I remember last time I tried to fix it - I ran in some kind of problem related to the fact, that processing of some of this fields have different logic in QuerySet and it's children, so reusing it caused some issues about joins not working properly or something like that

If you have time to experiment with that - you can try to fix it and create PR

@coveralls
Copy link

coveralls commented Oct 24, 2024

Pull Request Test Coverage Report for Build 11514953088

Details

  • 63 of 63 (100.0%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.003%) to 89.024%

Totals Coverage Status
Change from base Build 11435130298: 0.003%
Covered Lines: 5979
Relevant Lines: 6602

💛 - Coveralls

@henadzit henadzit force-pushed the feat/annotation-in-case-when branch from 0fa73d8 to 8b9e2f6 Compare October 25, 2024 08:46
@abondar abondar merged commit 5e3c6f8 into tortoise:develop Oct 26, 2024
7 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.

Can't use annotated field in CASE-WHEN Clause
3 participants