diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/dialects/postgresql/base.py | 46 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/postgresql/hstore.py | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/dialects/postgresql/json.py | 29 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 17 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/operators.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 6 |
6 files changed, 60 insertions, 51 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index e0f275a30..2ccc69341 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -1056,41 +1056,21 @@ class PGCompiler(compiler.SQLCompiler): self.process(element.stop, **kw), ) - def visit_custom_op_binary(self, binary, operator, **kw): - from .json import JSONPathType, ASTEXT - if operator is ASTEXT: - if isinstance(binary.right.type, JSONPathType): - opstring = "#>>" - else: - opstring = "->>" - return "%s %s %s" % ( - self.process(binary.left, **kw), - opstring, - self.process(binary.right, **kw) - ) - else: - return super(PGCompiler, self).visit_custom_op_binary( - binary, operator, **kw) + def visit_jsongetitem_binary(self, binary, operator, **kw): + return self._generate_generic_binary( + binary, " -> ", **kw + ) - def visit_getitem_binary(self, binary, operator, **kw): - from .json import JSONPathType, JSON - from .hstore import HSTORE - if isinstance(binary.left.type, (JSON, HSTORE)): - if isinstance(binary.right.type, JSONPathType): - opstring = "#>" - else: - opstring = "->" - return "%s %s %s" % ( - self.process(binary.left, **kw), - opstring, - self.process(binary.right, **kw) - ) + def visit_jsonpath_jsongetitem_binary(self, binary, operator, **kw): + return self._generate_generic_binary( + binary, " #> ", **kw + ) - else: - return "%s[%s]" % ( - self.process(binary.left, **kw), - self.process(binary.right, **kw) - ) + def visit_getitem_binary(self, binary, operator, **kw): + return "%s[%s]" % ( + self.process(binary.left, **kw), + self.process(binary.right, **kw) + ) def visit_aggregate_order_by(self, element, **kw): return "%s ORDER BY %s" % ( diff --git a/lib/sqlalchemy/dialects/postgresql/hstore.py b/lib/sqlalchemy/dialects/postgresql/hstore.py index 03d8017db..d2d20386a 100644 --- a/lib/sqlalchemy/dialects/postgresql/hstore.py +++ b/lib/sqlalchemy/dialects/postgresql/hstore.py @@ -12,14 +12,13 @@ from .array import ARRAY from ... import types as sqltypes from ...sql import functions as sqlfunc from ...sql import operators -from ...sql.operators import custom_op from ... import util __all__ = ('HSTORE', 'hstore') -INDEX = custom_op( - None, precedence=15, natural_self_precedent=True +GETITEM = operators.custom_op( + "->", precedence=15, natural_self_precedent=True, ) HAS_KEY = operators.custom_op( @@ -166,7 +165,7 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine): CONTAINED_BY, other, result_type=sqltypes.Boolean) def _setup_getitem(self, index): - return index, self.type.text_type + return GETITEM, index, self.type.text_type def defined(self, key): """Boolean expression. Test for presence of a non-NULL value for diff --git a/lib/sqlalchemy/dialects/postgresql/json.py b/lib/sqlalchemy/dialects/postgresql/json.py index 03c68d30c..a05c19d18 100644 --- a/lib/sqlalchemy/dialects/postgresql/json.py +++ b/lib/sqlalchemy/dialects/postgresql/json.py @@ -17,9 +17,22 @@ from ... import util __all__ = ('JSON', 'JSONB') +GETITEM = operators.custom_op( + None, precedence=15, natural_self_precedent=True, + visit_name='jsongetitem' +) + +JSONPATH_GETITEM = operators.custom_op( + None, precedence=15, natural_self_precedent=True, + visit_name='jsonpath_jsongetitem' +) ASTEXT = operators.custom_op( - None, precedence=15, natural_self_precedent=True + "->>", precedence=15, natural_self_precedent=True, +) + +JSONPATH_ASTEXT = operators.custom_op( + "#>>", precedence=15, natural_self_precedent=True, ) @@ -231,16 +244,24 @@ class JSON(sqltypes.Indexable, sqltypes.TypeEngine): """ - return self.expr.left.operate( - ASTEXT, self.expr.right, result_type=self.type.astext_type) + if isinstance(self.expr.right.type, JSONPathType): + return self.expr.left.operate( + JSONPATH_ASTEXT, + self.expr.right, result_type=self.type.astext_type) + else: + return self.expr.left.operate( + ASTEXT, self.expr.right, result_type=self.type.astext_type) def _setup_getitem(self, index): if not isinstance(index, util.string_types) and \ isinstance(index, collections.Sequence): index = self.expr._bind_param(operators.getitem, index) index.type = JSONPathType() + operator = JSONPATH_GETITEM + else: + operator = GETITEM - return index, self.type + return operator, index, self.type comparator_factory = Comparator diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 6766c99b7..60d300273 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -873,22 +873,29 @@ class SQLCompiler(Compiled): else: return text + def _get_operator_dispatch(self, operator_, qualifier1, qualifier2): + attrname = "visit_%s_%s%s" % ( + operator_.__visit_name__ if operator_.__name__ == 'custom_op' + else operator_.__name__, qualifier1, + "_" + qualifier2 if qualifier2 else "") + return getattr(self, attrname, None) + def visit_unary(self, unary, **kw): if unary.operator: if unary.modifier: raise exc.CompileError( "Unary expression does not support operator " "and modifier simultaneously") - disp = getattr(self, "visit_%s_unary_operator" % - unary.operator.__name__, None) + disp = self._get_operator_dispatch( + unary.operator, "unary", "operator") if disp: return disp(unary, unary.operator, **kw) else: return self._generate_generic_unary_operator( unary, OPERATORS[unary.operator], **kw) elif unary.modifier: - disp = getattr(self, "visit_%s_unary_modifier" % - unary.modifier.__name__, None) + disp = self._get_operator_dispatch( + unary.modifier, "unary", "modifier") if disp: return disp(unary, unary.modifier, **kw) else: @@ -922,7 +929,7 @@ class SQLCompiler(Compiled): kw['literal_binds'] = True operator_ = override_operator or binary.operator - disp = getattr(self, "visit_%s_binary" % operator_.__name__, None) + disp = self._get_operator_dispatch(operator_, "binary", None) if disp: return disp(binary, operator_, **kw) else: diff --git a/lib/sqlalchemy/sql/operators.py b/lib/sqlalchemy/sql/operators.py index da3576466..dd81473b9 100644 --- a/lib/sqlalchemy/sql/operators.py +++ b/lib/sqlalchemy/sql/operators.py @@ -12,7 +12,6 @@ from .. import util - from operator import ( and_, or_, inv, add, mul, sub, mod, truediv, lt, le, ne, gt, ge, eq, neg, getitem, lshift, rshift @@ -213,14 +212,17 @@ class custom_op(object): """ __name__ = 'custom_op' + __visit_name__ = 'custom_op' def __init__( self, opstring, precedence=0, is_comparison=False, - natural_self_precedent=False): + natural_self_precedent=False, visit_name=None): self.opstring = opstring self.precedence = precedence self.is_comparison = is_comparison self.natural_self_precedent = natural_self_precedent + if visit_name is not None: + self.__visit_name__ = visit_name def __eq__(self, other): return isinstance(other, custom_op) and \ diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 552e23285..514316c11 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -91,10 +91,10 @@ class Indexable(object): raise NotImplementedError() def __getitem__(self, index): - adjusted_right_expr, result_type = \ + adjusted_op, adjusted_right_expr, result_type = \ self._setup_getitem(index) return self.operate( - operators.getitem, + adjusted_op, adjusted_right_expr, result_type=result_type ) @@ -1628,7 +1628,7 @@ class Array(Indexable, Concatenable, TypeEngine): return_type = self.type.adapt( self.type.__class__, **adapt_kw) - return index, return_type + return operators.getitem, index, return_type @util.dependencies("sqlalchemy.sql.elements") def any(self, elements, other, operator=None): |
