From 8560db8bc13c6996b20c5269195a9b64e6a37348 Mon Sep 17 00:00:00 2001 From: AarDG10 Date: Sun, 29 Mar 2026 17:45:46 +0530 Subject: [PATCH 1/2] feat(custom): add separator support for Group_concat in Mariadb --- frappe/query_builder/custom.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/frappe/query_builder/custom.py b/frappe/query_builder/custom.py index faa1c4b37f..dc9c7f6354 100644 --- a/frappe/query_builder/custom.py +++ b/frappe/query_builder/custom.py @@ -15,6 +15,28 @@ class GROUP_CONCAT(DistinctOptionFunction): alias (Optional[str], optional): [ is this an alias? ]. Defaults to None. """ super().__init__("GROUP_CONCAT", column, alias=alias) + self._separator = "," + + @builder + def separator(self, separator: str = ""): + """Adds a separator to the GROUP_CONCAT function. + Args: + separator (str, optional): [separator to be used]. Defaults to ",". + """ + self._separator = separator + + def get_sql(self, **kwargs): + query_alias = self.alias + self.alias = None + sql = super().get_sql(**kwargs) + if self._separator: + sql = f"{sql[:-1]} SEPARATOR {frappe.db.escape(self._separator)})" + + self.alias = query_alias + if self.alias: + quote = kwargs.get("quote_char", "`") + sql += f" {quote}{self.alias}{quote}" + return sql class STRING_AGG(DistinctOptionFunction): From 12e899564080cb0ff4cff9fb694dabb62f3f1e38 Mon Sep 17 00:00:00 2001 From: AarDG10 Date: Sun, 29 Mar 2026 18:03:08 +0530 Subject: [PATCH 2/2] test: add and update group_concat test for mariadb Updated test, since have decided to keep separator ',' as default for the query generation. --- frappe/tests/test_query_builder.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_query_builder.py b/frappe/tests/test_query_builder.py index 9375d17ef2..42e6b87774 100644 --- a/frappe/tests/test_query_builder.py +++ b/frappe/tests/test_query_builder.py @@ -34,7 +34,12 @@ def unimplemented_for(*dbtypes: db_type_is) -> Callable: @run_only_if(db_type_is.MARIADB) class TestCustomFunctionsMariaDB(IntegrationTestCase): def test_concat(self): - self.assertEqual("GROUP_CONCAT('Notes')", GroupConcat("Notes").get_sql()) + self.assertEqual("GROUP_CONCAT('Notes' SEPARATOR ',')", GroupConcat("Notes").get_sql()) + user = frappe.qb.DocType("User") + query = frappe.qb.from_(user).select(GroupConcat(user.email).separator(" | ").as_("user_list")) + sql = query.get_sql() + self.assertIn("SEPARATOR ' | '", sql) + self.assertIn("`user_list`", sql) def test_match(self): query = Match("Notes")