Merge pull request #13841 from gavindsouza/execute-query
feat: Execute queries directly in frappe.qb
This commit is contained in:
commit
b6945a374a
9 changed files with 50 additions and 17 deletions
|
|
@ -28,7 +28,7 @@ from .exceptions import *
|
|||
from .utils.jinja import (get_jenv, get_template, render_template, get_email_from_template, get_jloader)
|
||||
from .utils.lazy_loader import lazy_import
|
||||
|
||||
from frappe.query_builder import get_query_builder
|
||||
from frappe.query_builder import get_query_builder, patch_query_execute
|
||||
|
||||
# Lazy imports
|
||||
faker = lazy_import('faker')
|
||||
|
|
@ -208,6 +208,7 @@ def init(site, sites_path=None, new_site=False):
|
|||
local.qb = get_query_builder(local.conf.db_type or "mariadb")
|
||||
|
||||
setup_module_map()
|
||||
patch_query_execute()
|
||||
|
||||
local.initialised = True
|
||||
|
||||
|
|
|
|||
|
|
@ -145,10 +145,9 @@ def build_table_count_cache():
|
|||
table_rows = frappe.qb.Field("table_rows").as_("count")
|
||||
information_schema = frappe.qb.Schema("information_schema")
|
||||
|
||||
query = frappe.qb.from_(information_schema.tables).select(table_name, table_rows)
|
||||
|
||||
data = frappe.db.sql(query, as_dict=1)
|
||||
|
||||
data = (
|
||||
frappe.qb.from_(information_schema.tables).select(table_name, table_rows)
|
||||
).run(as_dict=True)
|
||||
counts = {d.get('name').lstrip('tab'): d.get('count', None) for d in data}
|
||||
_cache.set_value("information_schema:counts", counts)
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,13 @@ def get_all_empty_tables_by_module():
|
|||
table_name = frappe.qb.Field("table_name")
|
||||
information_schema = frappe.qb.Schema("information_schema")
|
||||
|
||||
query = frappe.qb.from_(information_schema.tables).select(table_name).where(table_rows == 0)
|
||||
empty_tables = (
|
||||
frappe.qb.from_(information_schema.tables)
|
||||
.select(table_name)
|
||||
.where(table_rows == 0)
|
||||
).run()
|
||||
|
||||
empty_tables = {r[0] for r in frappe.db.sql(query)}
|
||||
empty_tables = {r[0] for r in empty_tables}
|
||||
|
||||
results = frappe.get_all("DocType", fields=["name", "module"])
|
||||
empty_tables_by_module = {}
|
||||
|
|
|
|||
|
|
@ -7,16 +7,14 @@ def execute():
|
|||
ToDo = frappe.qb.DocType("ToDo")
|
||||
assignees = GroupConcat("owner").distinct().as_("assignees")
|
||||
|
||||
query = (
|
||||
assignments = (
|
||||
frappe.qb.from_(ToDo)
|
||||
.select(ToDo.name, ToDo.reference_type, assignees)
|
||||
.where(Coalesce(ToDo.reference_type, "") != "")
|
||||
.where(Coalesce(ToDo.reference_name, "") != "")
|
||||
.where(ToDo.status != "Cancelled")
|
||||
.groupby(ToDo.reference_type, ToDo.reference_name)
|
||||
)
|
||||
|
||||
assignments = frappe.db.sql(query, as_dict=True)
|
||||
).run(as_dict=True)
|
||||
|
||||
for doc in assignments:
|
||||
assignments = doc.assignees.split(",")
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
from frappe.query_builder.utils import get_query_builder
|
||||
from frappe.query_builder.utils import get_query_builder, patch_query_execute
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from enum import Enum
|
||||
from typing import Any, Callable, Dict
|
||||
from typing import Any, Callable, Dict, get_type_hints
|
||||
from importlib import import_module
|
||||
|
||||
from pypika import Query
|
||||
|
||||
|
|
@ -19,6 +20,9 @@ class ImportMapper:
|
|||
db = db_type_is(frappe.conf.db_type or "mariadb")
|
||||
return self.func_map[db](*args, **kwds)
|
||||
|
||||
class BuilderIdentificationFailed(Exception):
|
||||
def __init__(self):
|
||||
super().__init__("Couldn't guess builder")
|
||||
|
||||
def get_query_builder(type_of_db: str) -> Query:
|
||||
"""[return the query builder object]
|
||||
|
|
@ -32,3 +36,25 @@ def get_query_builder(type_of_db: str) -> Query:
|
|||
db = db_type_is(type_of_db)
|
||||
picks = {db_type_is.MARIADB: MariaDB, db_type_is.POSTGRES: Postgres}
|
||||
return picks[db]
|
||||
|
||||
def get_attr(method_string):
|
||||
modulename = '.'.join(method_string.split('.')[:-1])
|
||||
methodname = method_string.split('.')[-1]
|
||||
return getattr(import_module(modulename), methodname)
|
||||
|
||||
def patch_query_execute():
|
||||
"""Patch the Query Builder with helper execute method
|
||||
This excludes the use of `frappe.db.sql` method while
|
||||
executing the query object
|
||||
"""
|
||||
|
||||
def execute_query(query, **kwargs):
|
||||
return frappe.db.sql(query, **kwargs)
|
||||
|
||||
query_class = get_attr(str(frappe.qb).split("'")[1])
|
||||
builder_class = get_type_hints(query_class._builder).get('return')
|
||||
|
||||
if not builder_class:
|
||||
raise BuilderIdentificationFailed
|
||||
|
||||
builder_class.run = execute_query
|
||||
|
|
|
|||
|
|
@ -42,6 +42,12 @@ class TestBuilderBase(object):
|
|||
self.assertEqual("__Auth", frappe.qb.DocType("__Auth").get_sql())
|
||||
self.assertEqual("Notes", frappe.qb.Table("Notes").get_sql())
|
||||
|
||||
def test_run_patcher(self):
|
||||
query = frappe.qb.from_("ToDo").select("*").limit(1)
|
||||
data = query.run(as_dict=True)
|
||||
self.assertTrue("run" in dir(query))
|
||||
self.assertIsInstance(query.run, Callable)
|
||||
self.assertIsInstance(data, list)
|
||||
|
||||
@run_only_if(db_type_is.MARIADB)
|
||||
class TestBuilderMaria(unittest.TestCase, TestBuilderBase):
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ def search(text, start=0, limit=20, doctype=""):
|
|||
if cint(start) > 0:
|
||||
query = query.offset(start)
|
||||
|
||||
result = frappe.db.sql(query, as_dict=True)
|
||||
result = query.run(as_dict=True)
|
||||
|
||||
results.extend(result)
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class WebsiteAnalytics(object):
|
|||
case = frappe.qb.terms.Case().when(WebPageView.is_unique == "1", "1")
|
||||
count_is_unique = Count(case).as_("unique_count")
|
||||
|
||||
query = (
|
||||
return (
|
||||
frappe.qb.from_(WebPageView)
|
||||
.select("path", count_all, count_is_unique)
|
||||
.where(
|
||||
|
|
@ -72,8 +72,7 @@ class WebsiteAnalytics(object):
|
|||
)
|
||||
.groupby(WebPageView.path)
|
||||
.orderby("count", Order=frappe.qb.desc)
|
||||
)
|
||||
return frappe.db.sql(query)
|
||||
).run()
|
||||
|
||||
def _get_query_for_mariadb(self):
|
||||
filters_range = self.filters.range
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue