Merge pull request #28015 from marination/not-set-filter

fix: 'not set' equivalence in query conditions
This commit is contained in:
Akhil Narang 2024-10-14 16:00:55 +05:30 committed by GitHub
commit e96ff7e65e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 20 additions and 3 deletions

View file

@ -8,6 +8,7 @@ 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
def like(key: Field, value: str) -> frappe.qb:
@ -94,7 +95,7 @@ def func_between(key: Field, value: list | tuple) -> frappe.qb:
def func_is(key, value):
"Wrapper for IS"
return key.isnotnull() if value.lower() == "set" else key.isnull()
return Coalesce(key, "") != "" if value.lower() == "set" else Coalesce(key, "") == ""
def func_timespan(key: Field, value: str) -> frappe.qb:

View file

@ -960,10 +960,12 @@ class TestDDLCommandsPost(IntegrationTestCase):
def test_is(self):
user = frappe.qb.DocType("User")
self.assertIn(
"is not null", frappe.db.get_values(user, filters={user.name: ("is", "set")}, run=False).lower()
'coalesce("name",',
frappe.db.get_values(user, filters={user.name: ("is", "set")}, run=False).lower(),
)
self.assertIn(
"is null", frappe.db.get_values(user, filters={user.name: ("is", "not set")}, run=False).lower()
'coalesce("name",',
frappe.db.get_values(user, filters={user.name: ("is", "not set")}, run=False).lower(),
)

View file

@ -1392,6 +1392,20 @@ class TestReportView(IntegrationTestCase):
response = execute_cmd("frappe.desk.reportview.get")
self.assertListEqual(response["keys"], ["published", "title", "test_field"])
def test_db_filter_not_set(self):
"""
Test if the 'not set' filter always translates correctly with/without qb under the hood.
"""
frappe.get_doc({"doctype": "ToDo", "description": "filter test"}).insert()
frappe.get_doc({"doctype": "ToDo", "description": "filter test", "reference_name": ""}).insert()
# `get_all` does not use QueryBuilder while `count` does. Both should return the same result.
# `not set` must consider empty strings and NULL values both.
self.assertEqual(
len(frappe.get_all("ToDo", filters={"reference_name": ["is", "not set"]})),
frappe.db.count("ToDo", {"reference_name": ["is", "not set"]}),
)
def add_child_table_to_blog_post():
child_table = frappe.get_doc(