Merge pull request #38128 from kaulith/fix/qb-in-filter-none-handling

This commit is contained in:
Hussain Nagaria 2026-03-27 18:12:11 +05:30 committed by GitHub
commit ac3d5ee115
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 70 additions and 1 deletions

View file

@ -3,7 +3,7 @@ frappe.ui.form.on("User", {
frm.set_query("default_workspace", () => {
return {
filters: {
for_user: ["in", [null, frappe.session.user]],
for_user: ["in", ["", frappe.session.user]],
title: ["!=", "Welcome Workspace"],
},
};

View file

@ -48,6 +48,10 @@ def func_in(key: Field, value: list | tuple) -> frappe.qb:
"""
if isinstance(value, str):
value = value.split(",")
value = ["" if v is None else v for v in value]
if "" in value:
return Coalesce(key, "").isin(value)
return key.isin(value)

View file

@ -4,6 +4,7 @@ from datetime import time
import frappe
from frappe.core.doctype.doctype.test_doctype import new_doctype
from frappe.database.operator_map import func_in
from frappe.query_builder import Case
from frappe.query_builder.builder import Function
from frappe.query_builder.custom import ConstantColumn
@ -503,3 +504,67 @@ class TestMisc(IntegrationTestCase):
roles = frappe.qb.from_(role).select(role.name)
self.assertEqual(set(users.run() + roles.run()), set((users + roles).run()))
class TestOperatorIn(IntegrationTestCase):
def test_func_in_without_empty_values(self):
note = frappe.qb.DocType("Note")
query = func_in(note.name, ["n1", "n2", "n3"])
sql_str = str(query).lower()
self.assertIn("in", sql_str)
self.assertNotIn("coalesce", sql_str)
def test_func_in_with_none_converts_to_empty_string(self):
note = frappe.qb.DocType("Note")
query = func_in(note.name, [None, "user1"])
sql_str = str(query).lower()
self.assertIn("coalesce", sql_str)
self.assertIn("''", sql_str)
def test_func_in_with_empty_string_uses_coalesce(self):
note = frappe.qb.DocType("Note")
query = func_in(note.name, ["", "user1"])
sql_str = str(query).lower()
self.assertIn("coalesce", sql_str)
self.assertIn("''", sql_str)
def test_func_in_with_mixed_none_and_values(self):
note = frappe.qb.DocType("Note")
query = func_in(note.name, ["val1", None, "val2"])
sql_str = str(query).lower()
self.assertIn("coalesce", sql_str)
def test_in_filter_matches_null_and_empty_columns(self):
test_doctype = new_doctype(
fields=[
{
"fieldname": "test_field",
"fieldtype": "Data",
"label": "Test Field",
},
],
)
test_doctype.insert()
self.test_doctype_name = test_doctype.name
self.addCleanup(frappe.delete_doc, "DocType", self.test_doctype_name)
doc_null = frappe.get_doc({"doctype": self.test_doctype_name, "test_field": None})
doc_null.insert()
doc_empty = frappe.get_doc({"doctype": self.test_doctype_name, "test_field": ""})
doc_empty.insert()
doc_user = frappe.get_doc({"doctype": self.test_doctype_name, "test_field": "user1"})
doc_user.insert()
results = frappe.get_all(
self.test_doctype_name,
filters={"test_field": ["in", [None, "user1"]]},
pluck="test_field",
)
self.assertIn(None, results)
self.assertIn("", results)
self.assertIn("user1", results)