From 51cfc8181e55fa09934363120e208fe9bbc14877 Mon Sep 17 00:00:00 2001 From: Kaushal Shriwas <64089478+kaulith@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:57:07 +0530 Subject: [PATCH] perf(query): replace Coalesce with OR IS NULL in func_in (#38336) --- frappe/database/operator_map.py | 3 +-- frappe/tests/test_query_builder.py | 11 +++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frappe/database/operator_map.py b/frappe/database/operator_map.py index c8cb9aa099..218983a318 100644 --- a/frappe/database/operator_map.py +++ b/frappe/database/operator_map.py @@ -8,7 +8,6 @@ import frappe from frappe.database.utils import NestedSetHierarchy from frappe.model.db_query import get_timespan_date_range from frappe.query_builder import Field -from frappe.query_builder.functions import Coalesce from frappe.utils import cstr @@ -51,7 +50,7 @@ def func_in(key: Field, value: list | tuple) -> frappe.qb: value = ["" if v is None else v for v in value] if "" in value: - return Coalesce(key, "").isin(value) + return key.isin(value) | key.isnull() return key.isin(value) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 920b06e4af..f0df927238 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -525,15 +525,17 @@ class TestOperatorIn(IntegrationTestCase): query = func_in(note.name, [None, "user1"]) sql_str = str(query).lower() - self.assertIn("coalesce", sql_str) + self.assertNotIn("coalesce", sql_str) + self.assertIn("is null", sql_str) self.assertIn("''", sql_str) - def test_func_in_with_empty_string_uses_coalesce(self): + def test_func_in_with_empty_string_uses_or_is_null(self): note = frappe.qb.DocType("Note") query = func_in(note.name, ["", "user1"]) sql_str = str(query).lower() - self.assertIn("coalesce", sql_str) + self.assertNotIn("coalesce", sql_str) + self.assertIn("is null", sql_str) self.assertIn("''", sql_str) def test_func_in_with_mixed_none_and_values(self): @@ -541,7 +543,8 @@ class TestOperatorIn(IntegrationTestCase): query = func_in(note.name, ["val1", None, "val2"]) sql_str = str(query).lower() - self.assertIn("coalesce", sql_str) + self.assertNotIn("coalesce", sql_str) + self.assertIn("is null", sql_str) def test_in_filter_matches_null_and_empty_columns(self): test_doctype = new_doctype(