diff --git a/tests/backends/mysql/test_operations.py b/tests/backends/mysql/test_operations.py index bd6170f299..2a50ec8583 100644 --- a/tests/backends/mysql/test_operations.py +++ b/tests/backends/mysql/test_operations.py @@ -1,7 +1,9 @@ import unittest +from datetime import datetime from django.core.management.color import no_style from django.db import connection +from django.db.backends.oracle.operations import DatabaseOperations from django.test import SimpleTestCase from ..models import Person, Tag @@ -45,3 +47,112 @@ class MySQLOperationsTests(SimpleTestCase): "SET FOREIGN_KEY_CHECKS = 1;", ], ) + + def test_date_extract_sql(self): + op = DatabaseOperations(connection=connection) + + # Test valid lookup types + valid_lookups = [ + "year", + "month", + "day", + "week_day", + "iso_week_day", + "week", + "quarter", + "iso_year", + "hour", + "minute", + "second", + ] + for lookup in valid_lookups: + with self.subTest(lookup=lookup): + sql, params = op.date_extract_sql(lookup, "test_date") + self.assertIn(lookup.upper(), sql) + self.assertEqual(params, ()) + + # Test invalid lookup type + with self.assertRaisesMessage( + ValueError, "Invalid lookup type: 'invalid_lookup'" + ): + op.date_extract_sql("invalid_lookup", "test_date") + + # Test that uppercase lookup types are accepted + sql, params = op.date_extract_sql("YEAR", "test_date") + self.assertIn("YEAR", sql) + self.assertEqual(params, ()) + + # Test that mixed case lookup types are not accepted + with self.assertRaisesMessage(ValueError, "Invalid lookup type: 'YeAr'"): + op.date_extract_sql("YeAr", "test_date") + + +class DatabaseOperationsTests(unittest.TestCase): + def setUp(self): + self.ops = DatabaseOperations(connection) + + def test_date_extract_sql(self): + # Test for various lookup types + test_cases = [ + ("year", "EXTRACT(YEAR FROM %s)", []), + ("quarter", "EXTRACT(QUARTER FROM %s)", []), + ("month", "EXTRACT(MONTH FROM %s)", []), + ("week", "EXTRACT(WEEK FROM %s)", []), + ("week_day", "DAYOFWEEK(%s)", []), + ("iso_week_day", "DAYOFWEEK(%s)", []), + ("day", "EXTRACT(DAY FROM %s)", []), + ("hour", "EXTRACT(HOUR FROM %s)", []), + ("minute", "EXTRACT(MINUTE FROM %s)", []), + ("second", "EXTRACT(SECOND FROM %s)", []), + ] + + for lookup_type, expected_sql, expected_params in test_cases: + with self.subTest(lookup_type=lookup_type): + sql, params = self.ops.date_extract_sql(lookup_type, "test_date") + self.assertEqual(sql, expected_sql) + self.assertEqual(params, expected_params) + + def test_date_extract_sql_invalid_lookup_type(self): + with self.assertRaises(ValueError): + self.ops.date_extract_sql("invalid", "test_date") + + def test_date_trunc_sql(self): + # Test for various lookup types + test_cases = [ + ("year", "DATE_TRUNC(%s, %%s)"), + ("quarter", "DATE_TRUNC(%s, %%s)"), + ("month", "DATE_TRUNC(%s, %%s)"), + ("week", "DATE_TRUNC(%s, %%s)"), + ("day", "DATE_TRUNC(%s, %%s)"), + ("hour", "DATE_TRUNC(%s, %%s)"), + ("minute", "DATE_TRUNC(%s, %%s)"), + ("second", "DATE_TRUNC(%s, %%s)"), + ] + + for lookup_type, expected_sql in test_cases: + with self.subTest(lookup_type=lookup_type): + sql = self.ops.date_trunc_sql(lookup_type, "test_date") + self.assertEqual(sql, expected_sql % lookup_type) + + def test_date_trunc_sql_invalid_lookup_type(self): + with self.assertRaises(ValueError): + self.ops.date_trunc_sql("invalid", "test_date") + + def test_datetime_cast_date_sql(self): + sql = self.ops.datetime_cast_date_sql("test_datetime", "test_tzname") + self.assertEqual(sql, "CAST(%s AS DATE)") + + def test_datetime_cast_time_sql(self): + sql = self.ops.datetime_cast_time_sql("test_datetime", "test_tzname") + self.assertEqual(sql, "CAST(%s AS TIME)") + + def test_datetime_extract_sql(self): + sql, params = self.ops.datetime_extract_sql( + "hour", "test_datetime", "test_tzname" + ) + self.assertEqual(sql, "EXTRACT(HOUR FROM %s)") + self.assertEqual(params, []) + + def test_datetime_trunc_sql(self): + sql = self.ops.datetime_trunc_sql("hour", "test_datetime", "test_tzname") + self.assertEqual(sql, "DATE_TRUNC(%s, %%s)") diff --git a/tests/backends/oracle/test_operations.py b/tests/backends/oracle/test_operations.py index 523bdcda8a..4ce6486836 100644 --- a/tests/backends/oracle/test_operations.py +++ b/tests/backends/oracle/test_operations.py @@ -1,7 +1,9 @@ import unittest +from datetime import datetime from django.core.management.color import no_style from django.db import connection +from django.db.backends.oracle.operations import DatabaseOperations from django.test import TransactionTestCase from ..models import Person, Tag @@ -11,6 +13,9 @@ from ..models import Person, Tag class OperationsTests(TransactionTestCase): available_apps = ["backends"] + def setUp(self): + self.ops = DatabaseOperations(connection=connection) + def test_sequence_name_truncation(self): seq_name = connection.ops._get_no_autofield_sequence_name( "schema_authorwithevenlongee869" @@ -141,3 +146,42 @@ class OperationsTests(TransactionTestCase): self.assertIn("BACKENDS_PERSON_SQ", statements[5]) self.assertIn("BACKENDS_VERYLONGMODELN7BE2_SQ", statements[6]) self.assertIn("BACKENDS_TAG_SQ", statements[7]) + + def test_date_extract_sql(self): + # Test for various lookup types + test_cases = [ + ("year", "TO_CHAR(test_date, %s)", ["YYYY"]), + ("quarter", "TO_CHAR(test_date, %s)", ["Q"]), + ("month", "TO_CHAR(test_date, %s)", ["MM"]), + ("week", "TO_CHAR(test_date, %s)", ["IW"]), + ("week_day", "TO_CHAR(test_date, %s)", ["D"]), + ("iso_week_day", "TO_CHAR(test_date - 1, %s)", ["D"]), + ("hour", "EXTRACT(HOUR FROM test_date)", []), + ("minute", "EXTRACT(MINUTE FROM test_date)", []), + ("second", "FLOOR(EXTRACT(SECOND FROM test_date))", []), + ("iso_year", "TO_CHAR(test_date, %s)", ["IYYY"]), + ] + + for lookup_type, expected_sql, expected_params in test_cases: + with self.subTest(lookup_type=lookup_type): + sql, params = self.ops.date_extract_sql(lookup_type, "test_date", []) + self.assertEqual(sql, expected_sql) + self.assertEqual(params, expected_params) + + def test_date_extract_sql_invalid_lookup_type(self): + with self.assertRaises(ValueError): + self.ops.date_extract_sql("invalid", "test_date", []) + + def test_date_extract_sql_with_timezone(self): + # Test that the method works correctly when a timezone is involved + sql, params = self.ops.date_extract_sql("hour", "test_date", ["UTC"]) + self.assertEqual(sql, "EXTRACT(HOUR FROM test_date)") + self.assertEqual(params, ["UTC"]) + + def test_date_extract_sql_params_passing(self): + # Test that additional parameters are correctly passed through + sql, params = self.ops.date_extract_sql( + "year", "test_date", ["param1", "param2"] + ) + self.assertEqual(sql, "TO_CHAR(test_date, %s)") + self.assertEqual(params, ["param1", "param2", "YYYY"])