From 8b47c6e5a084f8600a428d3703e162b2a941fe75 Mon Sep 17 00:00:00 2001 From: Aarol D'Souza <98270103+AarDG10@users.noreply.github.com> Date: Fri, 1 May 2026 18:15:23 +0530 Subject: [PATCH 1/2] Revert "fix(query): unique aliasing for linked field joins" --- frappe/database/query.py | 3 ++- frappe/tests/test_db_query.py | 10 ++-------- frappe/tests/test_query.py | 6 +++--- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/frappe/database/query.py b/frappe/database/query.py index 4d3f2ddd0b..5ed3e32664 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -2087,7 +2087,8 @@ class LinkTableField(DynamicTableField): def _get_joined_table(self): table = frappe.qb.DocType(self.doctype) - table = table.as_(f"tab{self.doctype}_{self.link_fieldname}") + if self.doctype == self.parent_doctype: + table = table.as_(f"tab{self.doctype}_{self.link_fieldname}") return table def apply_select(self, query: QueryBuilder, engine: "Engine" = None) -> QueryBuilder: diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index 1a05897c9c..27f9a1b201 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -1238,14 +1238,8 @@ class TestDBQuery(IntegrationTestCase): fields=fields, ).get_sql() - self.assertIn( - self.normalize_sql("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_parent_ref`"), - self.normalize_sql(query), - ) - self.assertIn( - self.normalize_sql("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_sibling_ref`"), - self.normalize_sql(query), - ) + self.assertIn("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_parent_ref`", query) + self.assertIn("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_sibling_ref`", query) def test_select_star_expansion(self): count = frappe.get_list("Language", [{"SUM": 1}, {"COUNT": "*"}], as_list=1, order_by=None)[0] diff --git a/frappe/tests/test_query.py b/frappe/tests/test_query.py index 18ab24c332..c413518642 100644 --- a/frappe/tests/test_query.py +++ b/frappe/tests/test_query.py @@ -371,10 +371,10 @@ class TestQuery(IntegrationTestCase): fields=["name"], filters={"module.app_name": "frappe"}, ).get_sql(), - "SELECT `tabDocType`.`name` FROM `tabDocType` LEFT JOIN `tabModule Def` `tabModule Def_module` ON `tabModule Def_module`.`name`=`tabDocType`.`module` WHERE `tabModule Def_module`.`app_name`='frappe'", + "SELECT `tabDocType`.`name` FROM `tabDocType` LEFT JOIN `tabModule Def` ON `tabModule Def`.`name`=`tabDocType`.`module` WHERE `tabModule Def`.`app_name`='frappe'", ) - query = "SELECT `tabDocType`.`name` FROM `tabDocType` LEFT JOIN `tabModule Def` `tabModule Def_module` ON `tabModule Def_module`.`name`=`tabDocType`.`module` WHERE `tabModule Def_module`.`app_name` LIKE 'frap%'" + query = "SELECT `tabDocType`.`name` FROM `tabDocType` LEFT JOIN `tabModule Def` ON `tabModule Def`.`name`=`tabDocType`.`module` WHERE `tabModule Def`.`app_name` LIKE 'frap%'" query = query.replace("LIKE", "ILIKE" if frappe.db.db_type == "postgres" else "LIKE") self.assertQueryEqual( frappe.qb.get_query( @@ -756,7 +756,7 @@ class TestQuery(IntegrationTestCase): "DocType", fields=["name", "module.app_name as app_name"], ).get_sql(), - "SELECT `tabDocType`.`name`,`tabModule Def_module`.`app_name` `app_name` FROM `tabDocType` LEFT JOIN `tabModule Def` `tabModule Def_module` ON `tabModule Def_module`.`name`=`tabDocType`.`module`", + "SELECT `tabDocType`.`name`,`tabModule Def`.`app_name` `app_name` FROM `tabDocType` LEFT JOIN `tabModule Def` ON `tabModule Def`.`name`=`tabDocType`.`module`", ) # fields now has strict validation, so this test is not valid anymore From 58d8859ddb2302a673c5bfad2f204843977ba6e1 Mon Sep 17 00:00:00 2001 From: AarDG10 Date: Fri, 1 May 2026 18:41:02 +0530 Subject: [PATCH 2/2] fix: revert some changes --- frappe/database/query.py | 12 ++----- frappe/tests/test_db_query.py | 62 ----------------------------------- 2 files changed, 3 insertions(+), 71 deletions(-) diff --git a/frappe/database/query.py b/frappe/database/query.py index 5ed3e32664..4d0ef0a78f 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -2082,22 +2082,16 @@ class LinkTableField(DynamicTableField): ) -> None: super().__init__(doctype, fieldname, parent_doctype, alias=alias) self.link_fieldname = link_fieldname - self.table = self._get_joined_table() + self.table = frappe.qb.DocType(self.doctype) self.field = self.table[self.fieldname] - def _get_joined_table(self): - table = frappe.qb.DocType(self.doctype) - if self.doctype == self.parent_doctype: - table = table.as_(f"tab{self.doctype}_{self.link_fieldname}") - return table - def apply_select(self, query: QueryBuilder, engine: "Engine" = None) -> QueryBuilder: - table = self._get_joined_table() + table = frappe.qb.DocType(self.doctype) query = self.apply_join(query, engine=engine) return query.select(getattr(table, self.fieldname).as_(self.alias or None)) def apply_join(self, query: QueryBuilder, engine: "Engine" = None) -> QueryBuilder: - table = self._get_joined_table() + table = frappe.qb.DocType(self.doctype) main_table = frappe.qb.DocType(self.parent_doctype) if not query.is_joined(table): query = query.left_join(table).on(table.name == getattr(main_table, self.link_fieldname)) diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index 27f9a1b201..c20b8aa9c1 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -1179,68 +1179,6 @@ class TestDBQuery(IntegrationTestCase): data = get() self.assertEqual(len(data["values"]), 1) - def test_self_referential_link_joins(self): - """Test that joined aliases are distinct, when a DocType has multiple links to itself.""" - - if not frappe.db.exists("DocType", "Self Linked DocType"): - frappe.get_doc( - { - "doctype": "DocType", - "custom": 1, - "module": "Custom", - "name": "Self Linked DocType", - "naming_rule": "Random", - "autoname": "hash", - "fields": [ - { - "label": "Title", - "fieldname": "title", - "fieldtype": "Data", - }, - { - "label": "Parent Ref", - "fieldname": "parent_ref", - "fieldtype": "Link", - "options": "Self Linked DocType", - }, - { - "label": "Sibling Ref", - "fieldname": "sibling_ref", - "fieldtype": "Link", - "options": "Self Linked DocType", - }, - ], - } - ).insert() - else: - frappe.db.delete("Self Linked DocType") - - first_link = frappe.get_doc({"doctype": "Self Linked DocType", "title": "Reference1"}).insert() - second_link = frappe.get_doc({"doctype": "Self Linked DocType", "title": "Reference2"}).insert() - frappe.get_doc( - { - "doctype": "Self Linked DocType", - "title": "Linked Doc", - "parent_ref": first_link.name, - "sibling_ref": second_link.name, - } - ).insert() - - fields = ["name", "parent_ref.title as parent_title", "sibling_ref.title as sibling_title"] - data = frappe.get_all( - "Self Linked DocType", - fields=fields, - ) - self.assertEqual(len(data), 3) - - query = frappe.qb.get_query( - "Self Linked DocType", - fields=fields, - ).get_sql() - - self.assertIn("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_parent_ref`", query) - self.assertIn("LEFT JOIN `tabSelf Linked DocType` `tabSelf Linked DocType_sibling_ref`", query) - def test_select_star_expansion(self): count = frappe.get_list("Language", [{"SUM": 1}, {"COUNT": "*"}], as_list=1, order_by=None)[0] self.assertEqual(count[0], frappe.db.count("Language"))