Files
sqlalchemy/test/orm/test_compile.py
T
Mike Bayer 75a3f84e5f - Improved checking for an existing backref name conflict during
mapper configuration; will now test for name conflicts on
superclasses and subclasses, in addition to the current mapper,
as these conflicts break things just as much.  This is new for
0.8, but see below for a warning that will also be triggered
in 0.7.11.
- Improved the error message emitted when a "backref loop" is detected,
that is when an attribute event triggers a bidirectional
assignment between two other attributes with no end.
This condition can occur not just when an object of the wrong
type is assigned, but also when an attribute is mis-configured
to backref into an existing backref pair.  Also in 0.7.11.
- A warning is emitted when a MapperProperty is assigned to a mapper
that replaces an existing property, if the properties in question
aren't plain column-based properties.   Replacement of relationship
properties is rarely (ever?) what is intended and usually refers to a
mapper mis-configuration.   Also in 0.7.11.
[ticket:2674]
2013-03-03 13:51:54 -05:00

214 lines
6.7 KiB
Python

from sqlalchemy import *
from sqlalchemy import exc as sa_exc
from sqlalchemy.orm import *
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import fixtures
from sqlalchemy import testing
class CompileTest(fixtures.ORMTest):
"""test various mapper compilation scenarios"""
def teardown(self):
clear_mappers()
def test_with_polymorphic(self):
metadata = MetaData(testing.db)
order = Table('orders', metadata,
Column('id', Integer, primary_key=True),
Column('employee_id', Integer, ForeignKey('employees.id'), nullable=False),
Column('type', Unicode(16)))
employee = Table('employees', metadata,
Column('id', Integer, primary_key=True),
Column('name', Unicode(16), unique=True, nullable=False))
product = Table('products', metadata,
Column('id', Integer, primary_key=True),
)
orderproduct = Table('orderproducts', metadata,
Column('id', Integer, primary_key=True),
Column('order_id', Integer, ForeignKey("orders.id"), nullable=False),
Column('product_id', Integer, ForeignKey("products.id"), nullable=False),
)
class Order(object):
pass
class Employee(object):
pass
class Product(object):
pass
class OrderProduct(object):
pass
order_join = order.select().alias('pjoin')
order_mapper = mapper(Order, order,
with_polymorphic=('*', order_join),
polymorphic_on=order_join.c.type,
polymorphic_identity='order',
properties={
'orderproducts': relationship(OrderProduct, lazy='select', backref='order')}
)
mapper(Product, product,
properties={
'orderproducts': relationship(OrderProduct, lazy='select', backref='product')}
)
mapper(Employee, employee,
properties={
'orders': relationship(Order, lazy='select', backref='employee')})
mapper(OrderProduct, orderproduct)
# this requires that the compilation of order_mapper's "surrogate
# mapper" occur after the initial setup of MapperProperty objects on
# the mapper.
configure_mappers()
def test_conflicting_backref_one(self):
"""test that conflicting backrefs raises an exception"""
metadata = MetaData(testing.db)
order = Table('orders', metadata,
Column('id', Integer, primary_key=True),
Column('type', Unicode(16)))
product = Table('products', metadata,
Column('id', Integer, primary_key=True),
)
orderproduct = Table('orderproducts', metadata,
Column('id', Integer, primary_key=True),
Column('order_id', Integer, ForeignKey("orders.id"), nullable=False),
Column('product_id', Integer, ForeignKey("products.id"), nullable=False),
)
class Order(object):
pass
class Product(object):
pass
class OrderProduct(object):
pass
order_join = order.select().alias('pjoin')
order_mapper = mapper(Order, order,
with_polymorphic=('*', order_join),
polymorphic_on=order_join.c.type,
polymorphic_identity='order',
properties={
'orderproducts': relationship(OrderProduct, lazy='select', backref='product')}
)
mapper(Product, product,
properties={
'orderproducts': relationship(OrderProduct, lazy='select', backref='product')}
)
mapper(OrderProduct, orderproduct)
assert_raises_message(
sa_exc.ArgumentError,
"Error creating backref",
configure_mappers
)
def test_misc_one(self):
metadata = MetaData(testing.db)
node_table = Table("node", metadata,
Column('node_id', Integer, primary_key=True),
Column('name_index', Integer, nullable=True),
)
node_name_table = Table("node_name", metadata,
Column('node_name_id', Integer, primary_key=True),
Column('node_id', Integer, ForeignKey('node.node_id')),
Column('host_id', Integer, ForeignKey('host.host_id')),
Column('name', String(64), nullable=False),
)
host_table = Table("host", metadata,
Column('host_id', Integer, primary_key=True),
Column('hostname', String(64), nullable=False,
unique=True),
)
metadata.create_all()
try:
node_table.insert().execute(node_id=1, node_index=5)
class Node(object):pass
class NodeName(object):pass
class Host(object):pass
node_mapper = mapper(Node, node_table)
host_mapper = mapper(Host, host_table)
node_name_mapper = mapper(NodeName, node_name_table,
properties = {
'node' : relationship(Node, backref=backref('names')),
'host' : relationship(Host),
}
)
sess = create_session()
assert sess.query(Node).get(1).names == []
finally:
metadata.drop_all()
def test_conflicting_backref_two(self):
meta = MetaData()
a = Table('a', meta, Column('id', Integer, primary_key=True))
b = Table('b', meta, Column('id', Integer, primary_key=True),
Column('a_id', Integer, ForeignKey('a.id')))
class A(object):
pass
class B(object):
pass
mapper(A, a, properties={
'b':relationship(B, backref='a')
})
mapper(B, b, properties={
'a':relationship(A, backref='b')
})
assert_raises_message(
sa_exc.ArgumentError,
"Error creating backref",
configure_mappers
)
def test_conflicting_backref_subclass(self):
meta = MetaData()
a = Table('a', meta, Column('id', Integer, primary_key=True))
b = Table('b', meta, Column('id', Integer, primary_key=True),
Column('a_id', Integer, ForeignKey('a.id')))
class A(object):
pass
class B(object):
pass
class C(B):
pass
mapper(A, a, properties={
'b': relationship(B, backref='a'),
'c': relationship(C, backref='a')
})
mapper(B, b)
mapper(C, None, inherits=B)
assert_raises_message(
sa_exc.ArgumentError,
"Error creating backref",
configure_mappers
)