From 9d3f410037b99f58b49ec2716a7147e5c8885593 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 23 Apr 2026 10:29:58 +0530 Subject: [PATCH] feat: add tests for JSON functions --- frappe/tests/test_query_builder.py | 75 ++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index f0df927238..0d7bcae136 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -14,6 +14,9 @@ from frappe.query_builder.functions import ( CombineDatetime, Date, GroupConcat, + JSONContains, + JSONExtract, + JSONValue, Match, Round, Truncate, @@ -176,6 +179,43 @@ class TestCustomFunctionsMariaDB(IntegrationTestCase): query = frappe.qb.from_(note).select(Truncate(note.price, 3)) self.assertEqual("select truncate(`price`,3) from `tabnote`", str(query).lower()) + def test_json_extract(self): + note = frappe.qb.DocType("Note") + # Simple get_sql + self.assertEqual("JSON_EXTRACT(content,'$.key')", JSONExtract(note.content, "$.key").get_sql()) + + # In a SELECT query + query = frappe.qb.from_(note).select(JSONExtract(note.content, "$.key")) + self.assertIn("json_extract(`content`,'$.key')", str(query).lower()) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONExtract(note.content, "$.key") == "value") + self.assertIn("json_extract(`content`,'$.key')='value'", str(query).lower()) + + def test_json_value(self): + note = frappe.qb.DocType("Note") + # Simple get_sql + self.assertEqual( + "JSON_UNQUOTE(JSON_EXTRACT(content,'$.key'))", JSONValue(note.content, "$.key").get_sql() + ) + + # In a SELECT query + query = frappe.qb.from_(note).select(JSONValue(note.content, "$.key")) + self.assertIn("json_unquote(json_extract(`content`,'$.key'))", str(query).lower()) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONValue(note.content, "$.key") == "value") + self.assertIn("json_unquote(json_extract(`content`,'$.key'))='value'", str(query).lower()) + + def test_json_contains(self): + note = frappe.qb.DocType("Note") + # With a plain string candidate (auto-wrapped as JSON) + self.assertEqual("JSON_CONTAINS(content,'\"value\"')", JSONContains(note.content, "value").get_sql()) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONContains(note.content, "admin")) + self.assertIn("json_contains(`content`,'\"admin\"')", str(query).lower()) + @run_only_if(db_type_is.POSTGRES) class TestCustomFunctionsPostgres(IntegrationTestCase): @@ -313,6 +353,41 @@ class TestCustomFunctionsPostgres(IntegrationTestCase): query = frappe.qb.from_(note).select(Truncate(note.price, 3)) self.assertEqual('select truncate("price",3) from "tabnote"', str(query).lower()) + def test_json_extract(self): + note = frappe.qb.DocType("Note") + # Simple get_sql + self.assertEqual("\"content\"->'$.key'", JSONExtract(note.content, "$.key").get_sql()) + + # In a SELECT query + query = frappe.qb.from_(note).select(JSONExtract(note.content, "$.key")) + self.assertIn("\"content\"->'$.key'", str(query)) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONExtract(note.content, "$.key") == "value") + self.assertIn("\"content\"->'$.key'='value'", str(query)) + + def test_json_value(self): + note = frappe.qb.DocType("Note") + # Simple get_sql + self.assertEqual("\"content\"->>'$.key'", JSONValue(note.content, "$.key").get_sql()) + + # In a SELECT query + query = frappe.qb.from_(note).select(JSONValue(note.content, "$.key")) + self.assertIn("\"content\"->>'$.key'", str(query)) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONValue(note.content, "$.key") == "value") + self.assertIn("\"content\"->>'$.key'='value'", str(query)) + + def test_json_contains(self): + note = frappe.qb.DocType("Note") + # With a plain string candidate + self.assertEqual("\"content\"@>'admin'", JSONContains(note.content, "admin").get_sql()) + + # In a WHERE clause + query = frappe.qb.from_(note).select(note.name).where(JSONContains(note.content, "admin")) + self.assertIn("\"content\"@>'admin'", str(query)) + class TestBuilderBase: def test_adding_tabs(self):