From 7c622942ca179ae4fba9102fdefc33233dbf21d9 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Wed, 18 Dec 2024 20:33:20 -0500 Subject: [PATCH 1/2] add TruncDate support --- README.md | 1 - django_mongodb/features.py | 8 +------- django_mongodb/functions.py | 23 +++++++++++++++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d41820995..907f5780b 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,6 @@ Congratulations, your project is ready to go! - `Right` - `SHA1`, `SHA224`, `SHA256`, `SHA384`, `SHA512` - `Sign` - - `TruncDate` - `TruncTime` - The `tzinfo` parameter of the `Trunc` database functions doesn't work diff --git a/django_mongodb/features.py b/django_mongodb/features.py index 433c9f009..fcd75a875 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -469,14 +469,8 @@ def django_test_expected_failures(self): "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_quarter_func", "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_extract_quarter_func_boundaries", }, - "TruncDate database function not supported.": { - "aggregation.tests.AggregateTestCase.test_aggregation_default_using_date_from_database", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_date_func", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_date_none", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_lookup_name_sql_injection", - "expressions.tests.FieldTransformTests.test_multiple_transforms_in_values", + "TruncDate database function's tzinfo not supported.": { "model_fields.test_datetimefield.DateTimeFieldTests.test_lookup_date_with_use_tz", - "model_fields.test_datetimefield.DateTimeFieldTests.test_lookup_date_without_use_tz", "timezones.tests.NewDatabaseTests.test_query_convert_timezones", }, "TruncTime database function not supported.": { diff --git a/django_mongodb/functions.py b/django_mongodb/functions.py index fc4057daa..eb08a854f 100644 --- a/django_mongodb/functions.py +++ b/django_mongodb/functions.py @@ -15,6 +15,7 @@ ExtractYear, Now, TruncBase, + TruncDate, ) from django.db.models.functions.math import Ceil, Cot, Degrees, Log, Power, Radians, Random, Round from django.db.models.functions.text import ( @@ -191,6 +192,27 @@ def trunc(self, compiler, connection): return {"$dateTrunc": lhs_mql} +def trunc_date(self, compiler, connection): + # Cast to date rather than truncate to date. + lhs_mql = process_lhs(self, compiler, connection) + tzname = self.get_tzname() + if tzname and tzname != "UTC": + raise NotSupportedError(f"TruncDate with tzinfo ({tzname}) isn't supported on MongoDB.") + return { + "$dateFromString": { + "dateString": { + "$concat": [ + {"$dateToString": {"format": "%Y-%m-%d", "date": lhs_mql}}, + # Dates are stored with time(0, 0), so by replacing any + # existing time component with that, the result of + # TruncDate can be compared to DateField. + "T00:00:00.000", + ] + }, + } + } + + def register_functions(): Cast.as_mql = cast Concat.as_mql = concat @@ -212,4 +234,5 @@ def register_functions(): Substr.as_mql = substr Trim.as_mql = trim("trim") TruncBase.as_mql = trunc + TruncDate.as_mql = trunc_date Upper.as_mql = preserve_null("toUpper") From c90a00c32851c983353b06abd77602c9e8393387 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Wed, 18 Dec 2024 21:07:32 -0500 Subject: [PATCH 2/2] add TruncTime support --- README.md | 1 - django_mongodb/features.py | 5 ----- django_mongodb/functions.py | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 907f5780b..79731cd10 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,6 @@ Congratulations, your project is ready to go! - `Right` - `SHA1`, `SHA224`, `SHA256`, `SHA384`, `SHA512` - `Sign` - - `TruncTime` - The `tzinfo` parameter of the `Trunc` database functions doesn't work properly because MongoDB converts the result back to UTC. diff --git a/django_mongodb/features.py b/django_mongodb/features.py index fcd75a875..4e585242c 100644 --- a/django_mongodb/features.py +++ b/django_mongodb/features.py @@ -473,11 +473,6 @@ def django_test_expected_failures(self): "model_fields.test_datetimefield.DateTimeFieldTests.test_lookup_date_with_use_tz", "timezones.tests.NewDatabaseTests.test_query_convert_timezones", }, - "TruncTime database function not supported.": { - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_comparison", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_func", - "db_functions.datetime.test_extract_trunc.DateFunctionTests.test_trunc_time_none", - }, "MongoDB can't annotate ($project) a function like PI().": { "aggregation.tests.AggregateTestCase.test_aggregation_default_using_decimal_from_database", "db_functions.math.test_pi.PiTests.test", diff --git a/django_mongodb/functions.py b/django_mongodb/functions.py index eb08a854f..750a548f8 100644 --- a/django_mongodb/functions.py +++ b/django_mongodb/functions.py @@ -16,6 +16,7 @@ Now, TruncBase, TruncDate, + TruncTime, ) from django.db.models.functions.math import Ceil, Cot, Degrees, Log, Power, Radians, Random, Round from django.db.models.functions.text import ( @@ -213,6 +214,23 @@ def trunc_date(self, compiler, connection): } +def trunc_time(self, compiler, connection): + lhs_mql = process_lhs(self, compiler, connection) + return { + "$dateFromString": { + "dateString": { + "$concat": [ + # Times are stored with date(1, 1, 1)), so by + # replacing any existing date component with that, the + # result of TruncTime can be compared to TimeField. + "0001-01-01T", + {"$dateToString": {"format": "%H:%M:%S.%L", "date": lhs_mql}}, + ] + } + } + } + + def register_functions(): Cast.as_mql = cast Concat.as_mql = concat @@ -235,4 +253,5 @@ def register_functions(): Trim.as_mql = trim("trim") TruncBase.as_mql = trunc TruncDate.as_mql = trunc_date + TruncTime.as_mql = trunc_time Upper.as_mql = preserve_null("toUpper")