Skip to content

Commit

Permalink
👌 IMPROVE: QueryBuilder reprs (incl/ queryhelp -> as_dict) (#5081)
Browse files Browse the repository at this point in the history
This commit improves the `QueryBuilder` methods
for serialising/deserialising instances and for analysing built queries:

1. Deprecates `queryhelp` for `as_dict()` and also add a `from_dict` classmethod:
   `queryhelp` is an unintuitive name, and a stumbling block for many new users.
2. Replace the `__str__` outputs with a representation of `as_dict()`,
   rather than the compiled SQL query (and also use this for `__repr__`):
   Users should not need to be exposed to the SQL, since this is a "dev-user" feature.
3. Add an `as_sql` method, for retrieving the SQL query string:
   This has an option to allow for both strings with the parameters inlined or external.
4. Improve the creation of the SQL string, to handle more data types.
5. Add the `analyze_query` method, to run postgresql's `EXPLAIN` command.
  • Loading branch information
chrisjsewell authored Aug 17, 2021
1 parent 74571a1 commit ccd5795
Show file tree
Hide file tree
Showing 16 changed files with 367 additions and 255 deletions.
18 changes: 8 additions & 10 deletions aiida/orm/implementation/django/querybuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
# For further information on the license, see the LICENSE.txt file #
# For further information please visit http://www.aiida.net #
###########################################################################
"""Django query builder"""
"""Django query builder implementation"""
from aldjemy import core
# Remove when https://github.com/PyCQA/pylint/issues/1931 is fixed
# pylint: disable=no-name-in-module, import-error
from sqlalchemy import and_, or_, not_, case
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.compiler import TypeCompiler
from sqlalchemy.sql.expression import FunctionElement
from sqlalchemy.types import Float, Boolean

Expand All @@ -26,45 +27,42 @@ class jsonb_array_length(FunctionElement): # pylint: disable=invalid-name


@compiles(jsonb_array_length)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined, redefined-builtin
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined, redefined-builtin
"""
Get length of array defined in a JSONB column
"""
return f'jsonb_array_length({compiler.process(element.clauses)})'
return f'jsonb_array_length({compiler.process(element.clauses, **kwargs)})'


class array_length(FunctionElement): # pylint: disable=invalid-name
name = 'array_len'


@compiles(array_length)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined
"""
Get length of array defined in a JSONB column
"""
return f'array_length({compiler.process(element.clauses)})'
return f'array_length({compiler.process(element.clauses, **kwargs)})'


class jsonb_typeof(FunctionElement): # pylint: disable=invalid-name
name = 'jsonb_typeof'


@compiles(jsonb_typeof)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined
"""
Get length of array defined in a JSONB column
"""
return f'jsonb_typeof({compiler.process(element.clauses)})'
return f'jsonb_typeof({compiler.process(element.clauses, **kwargs)})'


class DjangoQueryBuilder(BackendQueryBuilder):
"""Django query builder"""

# pylint: disable=too-many-public-methods,no-member

def __init__(self, backend):
BackendQueryBuilder.__init__(self, backend)

@property
def Node(self):
return models.DbNode.sa
Expand Down
15 changes: 8 additions & 7 deletions aiida/orm/implementation/sqlalchemy/querybuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from sqlalchemy.types import Float, Boolean
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.sql.expression import case, FunctionElement
from sqlalchemy.sql.compiler import TypeCompiler
from sqlalchemy.ext.compiler import compiles

from aiida.common.exceptions import NotExistent
Expand All @@ -24,35 +25,35 @@ class jsonb_array_length(FunctionElement): # pylint: disable=invalid-name


@compiles(jsonb_array_length)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined, redefined-builtin
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined, redefined-builtin
"""
Get length of array defined in a JSONB column
"""
return f'jsonb_array_length({compiler.process(element.clauses)})'
return f'jsonb_array_length({compiler.process(element.clauses, **kwargs)})'


class array_length(FunctionElement): # pylint: disable=invalid-name
name = 'array_len'


@compiles(array_length)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined
"""
Get length of array defined in a JSONB column
"""
return f'array_length({compiler.process(element.clauses)})'
return f'array_length({compiler.process(element.clauses, **kwargs)})'


class jsonb_typeof(FunctionElement): # pylint: disable=invalid-name
name = 'jsonb_typeof'


@compiles(jsonb_typeof)
def compile(element, compiler, **_kw): # pylint: disable=function-redefined
def compile(element, compiler: TypeCompiler, **kwargs): # pylint: disable=function-redefined
"""
Get length of array defined in a JSONB column
"""
return f'jsonb_typeof({compiler.process(element.clauses)})'
return f'jsonb_typeof({compiler.process(element.clauses, **kwargs)})'


class SqlaQueryBuilder(BackendQueryBuilder):
Expand All @@ -64,7 +65,7 @@ class SqlaQueryBuilder(BackendQueryBuilder):
# pylint: disable=redefined-outer-name,too-many-public-methods

def __init__(self, backend):
BackendQueryBuilder.__init__(self, backend)
super().__init__(backend)

self.outer_to_inner_schema['db_dbcomputer'] = {'metadata': '_metadata'}
self.outer_to_inner_schema['db_dblog'] = {'metadata': '_metadata'}
Expand Down
Loading

0 comments on commit ccd5795

Please sign in to comment.