From: Mike Bayer Date: Mon, 16 May 2022 02:24:40 +0000 (-0400) Subject: ensure MappedColumn col is mapped under alternate key X-Git-Tag: rel_2_0_0b1~310^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c05d3497aa3c6f8446e09c4201f270a0dc0626b8;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git ensure MappedColumn col is mapped under alternate key Fixes: #8025 Change-Id: I83ba54f05bd2e5fc87d80f42fbeb6d4d2f2ac5fa --- diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index b1f81cb6b8..fe5a20d04d 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -876,20 +876,27 @@ class _ClassScanMapperConfig(_MapperConfig): name_to_prop_key = collections.defaultdict(set) for key, c in list(our_stuff.items()): if isinstance(c, _MapsColumns): - for col in c.columns_to_assign: - if not isinstance(c, Composite): - name_to_prop_key[col.name].add(key) - declared_columns.add(col) - # remove object from the dictionary that will be passed - # as mapper(properties={...}) if it is not a MapperProperty - # (i.e. this currently means it's a MappedColumn) mp_to_assign = c.mapper_property_to_assign if mp_to_assign: our_stuff[key] = mp_to_assign else: + # if no mapper property to assign, this currently means + # this is a MappedColumn that will produce a Column for us del our_stuff[key] + for col in c.columns_to_assign: + if not isinstance(c, Composite): + name_to_prop_key[col.name].add(key) + declared_columns.add(col) + + # if this is a MappedColumn and the attribute key we + # have is not what the column has for its key, map the + # Column explicitly under the attribute key name. + # otherwise, Mapper will map it under the column key. + if mp_to_assign is None and key != col.key: + our_stuff[key] = col + elif isinstance(c, Column): # undefer previously occurred here, and now occurs earlier. # ensure every column we get here has been named diff --git a/test/orm/declarative/test_typed_mapping.py b/test/orm/declarative/test_typed_mapping.py index 2c9cc3b21b..4e36469d83 100644 --- a/test/orm/declarative/test_typed_mapping.py +++ b/test/orm/declarative/test_typed_mapping.py @@ -110,6 +110,36 @@ class MappedColumnTest(fixtures.TestBase, testing.AssertsCompiledSQL): id: Mapped[int] = mapped_column(primary_key=True) data = mapped_column() + @testing.combinations("key", "name", "both", argnames="case") + @testing.combinations(True, False, argnames="deferred") + @testing.combinations(True, False, argnames="use_add_property") + def test_separate_name(self, decl_base, case, deferred, use_add_property): + if case == "key": + args = {"key": "data_"} + elif case == "name": + args = {"name": "data_"} + else: + args = {"name": "data_", "key": "data_"} + + if deferred: + args["deferred"] = True + + class A(decl_base): + __tablename__ = "a" + + id: Mapped[int] = mapped_column(primary_key=True) + + if not use_add_property: + data: Mapped[str] = mapped_column(**args) + + if use_add_property: + args["type_"] = String() + A.data = mapped_column(**args) + + assert not hasattr(A, "data_") + is_(A.data.property.expression, A.__table__.c.data_) + eq_(A.__table__.c.data_.key, "data_") + def test_construct_rhs(self, decl_base): class User(decl_base): __tablename__ = "users"