summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py46
-rw-r--r--lib/sqlalchemy/dialects/postgresql/hstore.py7
-rw-r--r--lib/sqlalchemy/dialects/postgresql/json.py29
-rw-r--r--lib/sqlalchemy/sql/compiler.py17
-rw-r--r--lib/sqlalchemy/sql/operators.py6
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py6
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):