diff --git a/frappe/database/query.py b/frappe/database/query.py index 53ba59b690..ff0ec3b9f7 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -109,6 +109,7 @@ class Engine: self.parent_doctype = parent_doctype self.reference_doctype = reference_doctype self.apply_permissions = not ignore_permissions + self.function_aliases = set() if isinstance(table, Table): self.table = table @@ -841,6 +842,10 @@ class Engine: # For numeric field references, return as-is (will be handled by caller) return field_name + # Allow function aliases - return as Field (no table prefix) + if field_name in self.function_aliases: + return Field(field_name) + # Reject backticks if "`" in field_name: frappe.throw( @@ -1690,6 +1695,7 @@ class SQLFunctionParser: ) if alias: + self.engine.function_aliases.add(alias) return function_call.as_(alias) else: return function_call diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index df7f99e0b4..c40d5e9cac 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -1126,6 +1126,17 @@ class TestDBQuery(IntegrationTestCase): ): frappe.get_all("Virtual DocType", filters={"name": "test"}, fields=["name"], limit=1) + def test_function_alias_in_clauses(self): + result = frappe.get_list( + "ToDo", + fields=["status", {"COUNT": "1", "as": "count"}], + group_by="status", + order_by="count desc", + limit=1, + ) + self.assertTrue(result) + self.assertIn("count", result[0]) + def test_coalesce_with_in_ops(self): self.assertNotIn("ifnull", frappe.get_all("User", {"first_name": ("in", ["a", "b"])}, run=0)) self.assertIn("ifnull", frappe.get_all("User", {"first_name": ("in", ["a", None])}, run=0))