diff options
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r-- | lib/sqlalchemy/sql/coercions.py | 17 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/elements.py | 11 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/roles.py | 8 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/schema.py | 78 |
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: |