summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/coercions.py17
-rw-r--r--lib/sqlalchemy/sql/elements.py11
-rw-r--r--lib/sqlalchemy/sql/roles.py8
-rw-r--r--lib/sqlalchemy/sql/schema.py78
4 files changed, 59 insertions, 55 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index 95aee0468..b45ef3991 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -147,6 +147,13 @@ class RoleImpl(object):
raise exc.ArgumentError(msg, code=code)
+class _Deannotate(object):
+ def _post_coercion(self, resolved, **kw):
+ from .util import _deep_deannotate
+
+ return _deep_deannotate(resolved)
+
+
class _StringOnly(object):
def _resolve_for_clause_element(self, element, argname=None, **kw):
return self._literal_coercion(element, **kw)
@@ -461,7 +468,9 @@ class TruncatedLabelImpl(_StringOnly, RoleImpl, roles.TruncatedLabelRole):
return elements._truncated_label(element)
-class DDLExpressionImpl(_CoerceLiterals, RoleImpl, roles.DDLExpressionRole):
+class DDLExpressionImpl(
+ _Deannotate, _CoerceLiterals, RoleImpl, roles.DDLExpressionRole
+):
_coerce_consts = True
@@ -470,11 +479,15 @@ class DDLExpressionImpl(_CoerceLiterals, RoleImpl, roles.DDLExpressionRole):
class DDLConstraintColumnImpl(
- _ReturnsStringKey, RoleImpl, roles.DDLConstraintColumnRole
+ _Deannotate, _ReturnsStringKey, RoleImpl, roles.DDLConstraintColumnRole
):
pass
+class DDLReferredColumnImpl(DDLConstraintColumnImpl):
+ pass
+
+
class LimitOffsetImpl(RoleImpl, roles.LimitOffsetRole):
def _implicit_coercions(self, element, resolved, argname=None, **kw):
if resolved is None:
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index ba615bc3f..eda31dc61 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -3246,7 +3246,7 @@ class BinaryExpression(ColumnElement):
# refer to BinaryExpression directly and pass strings
if isinstance(operator, util.string_types):
operator = operators.custom_op(operator)
- self._orig = (left, right)
+ self._orig = (hash(left), hash(right))
self.left = left.self_group(against=operator)
self.right = right.self_group(against=operator)
self.operator = operator
@@ -3261,7 +3261,7 @@ class BinaryExpression(ColumnElement):
def __bool__(self):
if self.operator in (operator.eq, operator.ne):
- return self.operator(hash(self._orig[0]), hash(self._orig[1]))
+ return self.operator(self._orig[0], self._orig[1])
else:
raise TypeError("Boolean value of this clause is not defined")
@@ -3946,7 +3946,12 @@ class Label(HasMemoized, roles.LabeledColumnExprRole, ColumnElement):
return key, e
-class ColumnClause(roles.LabeledColumnExprRole, Immutable, ColumnElement):
+class ColumnClause(
+ roles.DDLReferredColumnRole,
+ roles.LabeledColumnExprRole,
+ Immutable,
+ ColumnElement,
+):
"""Represents a column expression from any textual string.
The :class:`.ColumnClause`, a lightweight analogue to the
diff --git a/lib/sqlalchemy/sql/roles.py b/lib/sqlalchemy/sql/roles.py
index 55c52d401..caa68d0ab 100644
--- a/lib/sqlalchemy/sql/roles.py
+++ b/lib/sqlalchemy/sql/roles.py
@@ -186,4 +186,10 @@ class DDLExpressionRole(StructuralRole):
class DDLConstraintColumnRole(SQLRole):
- _role_name = "String column name or column object for DDL constraint"
+ _role_name = "String column name or column expression for DDL constraint"
+
+
+class DDLReferredColumnRole(DDLConstraintColumnRole):
+ _role_name = (
+ "String column name or Column object for DDL foreign key constraint"
+ )
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 8c325538c..1d1ff96d8 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -1721,21 +1721,14 @@ class ForeignKey(DialectKWArgs, SchemaItem):
"""
- self._colspec = column
+ self._colspec = coercions.expect(roles.DDLReferredColumnRole, column)
+
if isinstance(self._colspec, util.string_types):
self._table_column = None
else:
- if hasattr(self._colspec, "__clause_element__"):
- self._table_column = self._colspec.__clause_element__()
- else:
- self._table_column = self._colspec
+ self._table_column = self._colspec
- if not isinstance(self._table_column, ColumnClause):
- raise exc.ArgumentError(
- "String, Column, or Column-bound argument "
- "expected, got %r" % self._table_column
- )
- elif not isinstance(
+ if not isinstance(
self._table_column.table, (util.NoneType, TableClause)
):
raise exc.ArgumentError(
@@ -2690,25 +2683,6 @@ class Constraint(DialectKWArgs, SchemaItem):
raise NotImplementedError()
-def _to_schema_column(element):
- if hasattr(element, "__clause_element__"):
- element = element.__clause_element__()
- if not isinstance(element, Column):
- raise exc.ArgumentError("schema.Column object expected")
- return element
-
-
-def _to_schema_column_or_string(element):
- if element is None:
- return element
- elif hasattr(element, "__clause_element__"):
- element = element.__clause_element__()
- if not isinstance(element, util.string_types + (ColumnElement,)):
- msg = "Element %r is not a string name or column element"
- raise exc.ArgumentError(msg % element)
- return element
-
-
class ColumnCollectionMixin(object):
columns = None
@@ -2725,9 +2699,26 @@ class ColumnCollectionMixin(object):
_autoattach = kw.pop("_autoattach", True)
self._column_flag = kw.pop("_column_flag", False)
self.columns = DedupeColumnCollection()
- self._pending_colargs = [
- _to_schema_column_or_string(c) for c in columns
- ]
+
+ processed_expressions = kw.pop("_gather_expressions", None)
+ if processed_expressions is not None:
+ self._pending_colargs = []
+ for (
+ expr,
+ column,
+ strname,
+ add_element,
+ ) in coercions.expect_col_expression_collection(
+ roles.DDLConstraintColumnRole, columns
+ ):
+ self._pending_colargs.append(add_element)
+ processed_expressions.append(expr)
+ else:
+ self._pending_colargs = [
+ coercions.expect(roles.DDLConstraintColumnRole, column)
+ for column in columns
+ ]
+
if _autoattach and self._pending_colargs:
self._check_attach()
@@ -2915,7 +2906,6 @@ class CheckConstraint(ColumnCollectionConstraint):
"""
self.sqltext = coercions.expect(roles.DDLExpressionRole, sqltext)
-
columns = []
visitors.traverse(self.sqltext, {}, {"column": columns.append})
@@ -3574,20 +3564,6 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
"""
self.table = table = None
- columns = []
- processed_expressions = []
- for (
- expr,
- column,
- strname,
- add_element,
- ) in coercions.expect_col_expression_collection(
- roles.DDLConstraintColumnRole, expressions
- ):
- columns.append(add_element)
- processed_expressions.append(expr)
-
- self.expressions = processed_expressions
self.name = quoted_name(name, kw.pop("quote", None))
self.unique = kw.pop("unique", False)
_column_flag = kw.pop("_column_flag", False)
@@ -3601,10 +3577,14 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
self._validate_dialect_kwargs(kw)
+ self.expressions = []
# will call _set_parent() if table-bound column
# objects are present
ColumnCollectionMixin.__init__(
- self, *columns, _column_flag=_column_flag
+ self,
+ *expressions,
+ _column_flag=_column_flag,
+ _gather_expressions=self.expressions
)
if table is not None: