summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-07-16 16:19:15 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2022-07-16 17:41:09 -0400
commit26c0e8e1846a4e6ac05c15a1ad188a5655b72edb (patch)
treed05ce7944e0c2107acd7457e1b086a8622e1d1cc /lib/sqlalchemy/sql
parent6104c163eb58e35e46b0bb6a237e824ec1ee1d15 (diff)
downloadsqlalchemy-26c0e8e1846a4e6ac05c15a1ad188a5655b72edb.tar.gz
implement column._merge()
this takes the user-defined args of one Column and merges them into the not-user-defined args of another Column. Implemented within the pep-593 column transfer operation to begin to make this new feature more robust. work may still be needed for constraints etc. but in theory everything from the left side annotated column should take effect for the right side if not otherwise specified on the right. Change-Id: I57eb37ed6ceb4b60979a35cfc4b63731d990911d
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/schema.py113
1 files changed, 112 insertions, 1 deletions
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 979b8319e..4ed5b9e6b 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -2233,6 +2233,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
server_default = self.server_default
server_onupdate = self.server_onupdate
if isinstance(server_default, (Computed, Identity)):
+ # TODO: likely should be copied in all cases
args.append(server_default._copy(**kw))
server_default = server_onupdate = None
@@ -2243,6 +2244,10 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
if self._user_defined_nullable is not NULL_UNSPECIFIED:
column_kwargs["nullable"] = self._user_defined_nullable
+ # TODO: DefaultGenerator is not copied here! it's just used again
+ # with _set_parent() pointing to the old column. see the new
+ # use of _copy() in the new _merge() method
+
c = self._constructor(
name=self.name,
type_=type_,
@@ -2264,6 +2269,69 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
)
return self._schema_item_copy(c)
+ def _merge(self, other: Column[Any]) -> None:
+ """merge the elements of another column into this one.
+
+ this is used by ORM pep-593 merge and will likely need a lot
+ of fixes.
+
+
+ """
+
+ if self.primary_key:
+ other.primary_key = True
+
+ type_ = self.type
+ if not type_._isnull and other.type._isnull:
+ if isinstance(type_, SchemaEventTarget):
+ type_ = type_.copy()
+
+ other.type = type_
+
+ if isinstance(type_, SchemaEventTarget):
+ type_._set_parent_with_dispatch(other)
+
+ for impl in type_._variant_mapping.values():
+ if isinstance(impl, SchemaEventTarget):
+ impl._set_parent_with_dispatch(other)
+
+ if (
+ self._user_defined_nullable is not NULL_UNSPECIFIED
+ and other._user_defined_nullable is NULL_UNSPECIFIED
+ ):
+ other.nullable = self.nullable
+
+ if self.default is not None and other.default is None:
+ new_default = self.default._copy()
+ new_default._set_parent(other)
+
+ if self.server_default and other.server_default is None:
+ new_server_default = self.server_default
+ if isinstance(new_server_default, FetchedValue):
+ new_server_default = new_server_default._copy()
+ new_server_default._set_parent(other)
+ else:
+ other.server_default = new_server_default
+
+ if self.server_onupdate and other.server_onupdate is None:
+ new_server_onupdate = self.server_onupdate
+ new_server_onupdate = new_server_onupdate._copy()
+ new_server_onupdate._set_parent(other)
+
+ if self.onupdate and other.onupdate is None:
+ new_onupdate = self.onupdate._copy()
+ new_onupdate._set_parent(other)
+
+ for const in self.constraints:
+ if not const._type_bound:
+ new_const = const._copy()
+ new_const._set_parent(other)
+
+ for fk in self.foreign_keys:
+ if not fk.constraint:
+ new_fk = fk._copy()
+ new_fk._set_parent(other)
+
def _make_proxy(
self,
selectable: FromClause,
@@ -2948,6 +3016,9 @@ class DefaultGenerator(Executable, SchemaItem):
else:
self.column.default = self
+ def _copy(self) -> DefaultGenerator:
+ raise NotImplementedError()
+
def _execute_on_connection(
self,
connection: Connection,
@@ -3077,6 +3148,11 @@ class ScalarElementColumnDefault(ColumnDefault):
self.for_update = for_update
self.arg = arg
+ def _copy(self) -> ScalarElementColumnDefault:
+ return ScalarElementColumnDefault(
+ arg=self.arg, for_update=self.for_update
+ )
+
# _SQLExprDefault = Union["ColumnElement[Any]", "TextClause", "SelectBase"]
_SQLExprDefault = Union["ColumnElement[Any]", "TextClause"]
@@ -3101,6 +3177,11 @@ class ColumnElementColumnDefault(ColumnDefault):
self.for_update = for_update
self.arg = arg
+ def _copy(self) -> ColumnElementColumnDefault:
+ return ColumnElementColumnDefault(
+ arg=self.arg, for_update=self.for_update
+ )
+
@util.memoized_property
@util.preload_module("sqlalchemy.sql.sqltypes")
def _arg_is_typed(self) -> bool:
@@ -3132,6 +3213,9 @@ class CallableColumnDefault(ColumnDefault):
self.for_update = for_update
self.arg = self._maybe_wrap_callable(arg)
+ def _copy(self) -> CallableColumnDefault:
+ return CallableColumnDefault(arg=self.arg, for_update=self.for_update)
+
def _maybe_wrap_callable(
self, fn: Union[_CallableColumnDefaultProtocol, Callable[[], Any]]
) -> _CallableColumnDefaultProtocol:
@@ -3266,7 +3350,7 @@ class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator):
nomaxvalue: Optional[bool] = None,
cycle: Optional[bool] = None,
schema: Optional[Union[str, Literal[SchemaConst.BLANK_SCHEMA]]] = None,
- cache: Optional[bool] = None,
+ cache: Optional[int] = None,
order: Optional[bool] = None,
data_type: Optional[_TypeEngineArgument[int]] = None,
optional: bool = False,
@@ -3459,6 +3543,25 @@ class Sequence(HasSchemaAttr, IdentityOptions, DefaultGenerator):
super(Sequence, self)._set_parent(column)
column._on_table_attach(self._set_table)
+ def _copy(self) -> Sequence:
+ return Sequence(
+ name=self.name,
+ start=self.start,
+ increment=self.increment,
+ minvalue=self.minvalue,
+ maxvalue=self.maxvalue,
+ nominvalue=self.nominvalue,
+ nomaxvalue=self.nomaxvalue,
+ cycle=self.cycle,
+ schema=self.schema,
+ cache=self.cache,
+ order=self.order,
+ data_type=self.data_type,
+ optional=self.optional,
+ metadata=self.metadata,
+ for_update=self.for_update,
+ )
+
def _set_table(self, column: Column[Any], table: Table) -> None:
self._set_metadata(table.metadata)
@@ -3522,6 +3625,9 @@ class FetchedValue(SchemaEventTarget):
else:
return self._clone(for_update) # type: ignore
+ def _copy(self) -> FetchedValue:
+ return FetchedValue(self.for_update)
+
def _clone(self, for_update: bool) -> Any:
n = self.__class__.__new__(self.__class__)
n.__dict__.update(self.__dict__)
@@ -3577,6 +3683,11 @@ class DefaultClause(FetchedValue):
self.arg = arg
self.reflected = _reflected
+ def _copy(self) -> DefaultClause:
+ return DefaultClause(
+ arg=self.arg, for_update=self.for_update, _reflected=self.reflected
+ )
+
def __repr__(self) -> str:
return "DefaultClause(%r, for_update=%r)" % (self.arg, self.for_update)