From 624e68c792759768895f54bee4059e879a565dae Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Sun, 15 May 2022 16:31:37 +0530 Subject: [PATCH 1/9] test: custom function --- frappe/tests/test_query_builder.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 45b1922767..7307ea1e08 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -253,3 +253,10 @@ class TestBuilderPostgres(unittest.TestCase, TestBuilderBase): def test_replace_fields_post(self): self.assertEqual("relname", frappe.qb.Field("table_name").get_sql()) + + +class TestMisc(unittest.TestCase): + def test_custom_func(self): + rand_func = frappe.qb.functions("rand", "45") + self.assertIsInstance(rand_func, Function) + self.assertEqual(rand_func.get_sql(), "rand('45')") From 98d21827b328b2d2deb769f19685591a3eba9ae3 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Sun, 15 May 2022 16:32:05 +0530 Subject: [PATCH 2/9] test: custom func with schema --- frappe/tests/test_query_builder.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 7307ea1e08..af02e00d91 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -163,7 +163,7 @@ class TestParameterization(unittest.TestCase): self.assertIn("param1", params) self.assertEqual(params["param1"], "Administrator' --") - def test_set_cnoditions(self): + def test_set_conditions(self): DocType = frappe.qb.DocType("DocType") query = frappe.qb.update(DocType).set(DocType.value, "some_value") @@ -260,3 +260,10 @@ class TestMisc(unittest.TestCase): rand_func = frappe.qb.functions("rand", "45") self.assertIsInstance(rand_func, Function) self.assertEqual(rand_func.get_sql(), "rand('45')") + + def test_function_with_schema(self): + from frappe.query_builder import ParameterizedFunction + + x = ParameterizedFunction("rand", "45") + x.schema = frappe.qb.DocType("DocType") + self.assertEqual("tabDocType.rand('45')", x.get_sql()) From e59c2f7b0400f8e5c224a450c58b3b9d75ba0b21 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Sun, 15 May 2022 16:33:00 +0530 Subject: [PATCH 3/9] test: match edge case --- frappe/query_builder/custom.py | 2 +- frappe/tests/test_query_builder.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frappe/query_builder/custom.py b/frappe/query_builder/custom.py index b0c8f863d3..20827df190 100644 --- a/frappe/query_builder/custom.py +++ b/frappe/query_builder/custom.py @@ -45,7 +45,7 @@ class MATCH(DistinctOptionFunction): if self._Against: return f"{s} AGAINST ({frappe.db.escape(f'+{self._Against}*')} IN BOOLEAN MODE)" - return s + raise Exception("Chain the `Against()` method with match to complete the query") @builder def Against(self, text: str): diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index af02e00d91..64bd4158e4 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -3,6 +3,7 @@ from typing import Callable import frappe from frappe.query_builder import Case +from frappe.query_builder.builder import Function from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.functions import Cast_, Coalesce, CombineDatetime, GroupConcat, Match from frappe.query_builder.utils import db_type_is @@ -18,7 +19,10 @@ class TestCustomFunctionsMariaDB(unittest.TestCase): self.assertEqual("GROUP_CONCAT('Notes')", GroupConcat("Notes").get_sql()) def test_match(self): - query = Match("Notes").Against("text") + query = Match("Notes") + with self.assertRaises(Exception): + query.get_sql() + query = query.Against("text") self.assertEqual(" MATCH('Notes') AGAINST ('+text*' IN BOOLEAN MODE)", query.get_sql()) def test_constant_column(self): @@ -81,6 +85,8 @@ class TestCustomFunctionsPostgres(unittest.TestCase): self.assertEqual("STRING_AGG('Notes',',')", GroupConcat("Notes").get_sql()) def test_match(self): + query = Match("Notes") + self.assertEqual("TO_TSVECTOR('Notes')", query.get_sql()) query = Match("Notes").Against("text") self.assertEqual("TO_TSVECTOR('Notes') @@ PLAINTO_TSQUERY('text')", query.get_sql()) From 846b89a703401c298ade62fe5c965618d8c2713a Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 03:13:37 +0530 Subject: [PATCH 4/9] test: test cast funtion --- frappe/query_builder/functions.py | 3 ++- frappe/tests/test_query_builder.py | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/frappe/query_builder/functions.py b/frappe/query_builder/functions.py index ee4ae6c30b..0ae8dc138d 100644 --- a/frappe/query_builder/functions.py +++ b/frappe/query_builder/functions.py @@ -1,6 +1,7 @@ from pypika.functions import * from pypika.terms import Arithmetic, ArithmeticExpression, CustomFunction, Function +import frappe from frappe.database.query import Query from frappe.query_builder.custom import GROUP_CONCAT, MATCH, STRING_AGG, TO_TSVECTOR from frappe.query_builder.utils import ImportMapper, db_type_is @@ -45,7 +46,7 @@ DateFormat = ImportMapper( class Cast_(Function): def __init__(self, value, as_type, alias=None): - if db_type_is.MARIADB and ( + if frappe.db.db_type == "mariadb" and ( (hasattr(as_type, "get_sql") and as_type.get_sql().lower() == "varchar") or str(as_type).lower() == "varchar" ): diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 64bd4158e4..a73da1f11f 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -75,8 +75,12 @@ class TestCustomFunctionsMariaDB(unittest.TestCase): def test_cast(self): note = frappe.qb.DocType("Note") - self.assertEqual("CONCAT(`tabnote`.`name`, '')", Cast_(note.name, "varchar")) - self.assertEqual("CAST(`tabnote`.`name` AS INTEGER)", Cast_(note.name, "integer")) + self.assertEqual("CONCAT(name,'')", Cast_(note.name, "varchar").get_sql()) + self.assertEqual("CAST(name AS INTEGER)", Cast_(note.name, "integer").get_sql()) + self.assertEqual( + frappe.qb.from_("red").from_(note).select("other", Cast_(note.name, "varchar")).get_sql(), + "SELECT `tabred`.`other`,CONCAT(`tabNote`.`name`,'') FROM `tabred`,`tabNote`", + ) @run_only_if(db_type_is.POSTGRES) @@ -138,8 +142,12 @@ class TestCustomFunctionsPostgres(unittest.TestCase): def test_cast(self): note = frappe.qb.DocType("Note") - self.assertEqual("CAST(`tabnote`.`name` AS VARCHAR)", Cast_(note.name, "varchar")) - self.assertEqual("CAST(`tabnote`.`name` AS INTEGER)", Cast_(note.name, "integer")) + self.assertEqual("CAST(name AS VARCHAR)", Cast_(note.name, "varchar").get_sql()) + self.assertEqual("CAST(name AS INTEGER)", Cast_(note.name, "integer").get_sql()) + self.assertEqual( + frappe.qb.from_("red").from_(note).select("other", Cast_(note.name, "varchar")).get_sql(), + 'SELECT "tabred"."other",CAST("tabNote"."name" AS VARCHAR) FROM "tabred","tabNote"', + ) class TestBuilderBase(object): From 1df3e8f5e700955d8f6d71d1fb93a1403dac6f4a Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 07:14:53 +0530 Subject: [PATCH 5/9] test: test agg funtions --- frappe/query_builder/functions.py | 7 +++++-- frappe/tests/test_query_builder.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/frappe/query_builder/functions.py b/frappe/query_builder/functions.py index 0ae8dc138d..f03c139f57 100644 --- a/frappe/query_builder/functions.py +++ b/frappe/query_builder/functions.py @@ -6,7 +6,7 @@ from frappe.database.query import Query from frappe.query_builder.custom import GROUP_CONCAT, MATCH, STRING_AGG, TO_TSVECTOR from frappe.query_builder.utils import ImportMapper, db_type_is -from .utils import Column +from .utils import PseudoColumn class Concat_ws(Function): @@ -73,7 +73,10 @@ class Cast_(Function): def _aggregate(function, dt, fieldname, filters, **kwargs): return ( - Query().build_conditions(dt, filters).select(function(Column(fieldname))).run(**kwargs)[0][0] + Query() + .build_conditions(dt, filters) + .select(function(PseudoColumn(fieldname))) + .run(**kwargs)[0][0] or 0 ) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index a73da1f11f..e15245422c 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -1,4 +1,5 @@ import unittest +from random import sample from typing import Callable import frappe @@ -163,6 +164,25 @@ class TestBuilderBase(object): self.assertIsInstance(query.run, Callable) self.assertIsInstance(data, list) + def test_agg_funcs(self): + frappe.db.truncate("Communication") + sample_data = { + "doctype": "Communication", + "communication_type": "Communication", + "content": "testing", + "rating": 1, + } + frappe.get_doc(sample_data).insert() + sample_data["rating"] = 3 + frappe.get_doc(sample_data).insert() + sample_data["rating"] = 4 + frappe.get_doc(sample_data).insert() + self.assertEqual(frappe.qb.max("Communication", "rating"), 4) + self.assertEqual(frappe.qb.min("Communication", "rating"), 1) + self.assertAlmostEqual(frappe.qb.avg("Communication", "rating"), 2.666, places=2) + self.assertEqual(frappe.qb.sum("Communication", "rating"), 8.0) + frappe.db.rollback() + class TestParameterization(unittest.TestCase): def test_where_conditions(self): From f4f42ba91ce049a05fce5d2e8cd5736333383988 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 11:26:05 +0530 Subject: [PATCH 6/9] test: NamedParameterWrapper --- frappe/tests/test_query_builder.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index e15245422c..ae33fcd313 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -1,3 +1,4 @@ +import re import unittest from random import sample from typing import Callable @@ -264,6 +265,19 @@ class TestParameterization(unittest.TestCase): self.assertEqual(params["param4"], "true_value") self.assertEqual(params["param5"], "Overdue") + def test_named_parameter_wrapper(self): + from frappe.query_builder.terms import NamedParameterWrapper + + test_npw = NamedParameterWrapper() + self.assertTrue(hasattr(test_npw, "parameters")) + self.assertEqual(test_npw.get_sql("test_string_one"), "%(param1)s") + self.assertEqual(test_npw.get_sql("test_string_two"), "%(param2)s") + params = test_npw.get_parameters() + for key in params.keys(): + # checks for param# format + self.assertRegex(key, r"param\d") + self.assertEqual(params["param1"], "test_string_one") + @run_only_if(db_type_is.MARIADB) class TestBuilderMaria(unittest.TestCase, TestBuilderBase): From 2578868f3ff6135fb23e06a11c9093ab1ca09e3d Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 14:42:16 +0530 Subject: [PATCH 7/9] test: Table() from utils --- frappe/tests/test_query_builder.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index ae33fcd313..dcbcbcd99e 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -1,6 +1,4 @@ -import re import unittest -from random import sample from typing import Callable import frappe @@ -315,3 +313,9 @@ class TestMisc(unittest.TestCase): x = ParameterizedFunction("rand", "45") x.schema = frappe.qb.DocType("DocType") self.assertEqual("tabDocType.rand('45')", x.get_sql()) + + def test_util_table(self): + from frappe.query_builder.utils import Table + + DocType = Table("DocType") + self.assertEqual(DocType.get_sql(), "DocType") From 81aed8f900224263fb1204ef0da3dc4daa5d22ef Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 14:43:29 +0530 Subject: [PATCH 8/9] test: patch_query_execute error case --- frappe/tests/test_query_builder.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index dcbcbcd99e..6175828bca 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -319,3 +319,11 @@ class TestMisc(unittest.TestCase): DocType = Table("DocType") self.assertEqual(DocType.get_sql(), "DocType") + + def test_error_on_query_class(self): + import frappe.query_builder.utils + + frappe.query_builder.utils.get_type_hints = lambda x: {"return": None} + + with self.assertRaises(frappe.query_builder.utils.BuilderIdentificationFailed): + frappe.query_builder.utils.patch_query_execute() From 21890884598a1e94517b6b3e759ee7684c3c5902 Mon Sep 17 00:00:00 2001 From: saxenabhishek Date: Mon, 16 May 2022 14:43:50 +0530 Subject: [PATCH 9/9] test: get_query_builder --- frappe/tests/test_query_builder.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 6175828bca..926bdedfbd 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -283,6 +283,12 @@ class TestBuilderMaria(unittest.TestCase, TestBuilderBase): self.assertEqual("SELECT * FROM `tabNotes`", frappe.qb.from_("Notes").select("*").get_sql()) self.assertEqual("SELECT * FROM `__Auth`", frappe.qb.from_("__Auth").select("*").get_sql()) + def test_get_qb_type(self): + from frappe.query_builder import get_query_builder + + qb = get_query_builder(frappe.db.db_type) + self.assertEqual("SELECT * FROM `tabDocType`", qb().from_("DocType").select("*").get_sql()) + @run_only_if(db_type_is.POSTGRES) class TestBuilderPostgres(unittest.TestCase, TestBuilderBase): @@ -300,6 +306,12 @@ class TestBuilderPostgres(unittest.TestCase, TestBuilderBase): def test_replace_fields_post(self): self.assertEqual("relname", frappe.qb.Field("table_name").get_sql()) + def test_get_qb_type(self): + from frappe.query_builder import get_query_builder + + qb = get_query_builder(frappe.db.db_type) + self.assertEqual('SELECT * FROM "tabDocType"', qb().from_("DocType").select("*").get_sql()) + class TestMisc(unittest.TestCase): def test_custom_func(self):