from sqlalchemy import Column
from sqlalchemy import exc as sa_exc
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import Unicode
from sqlalchemy.orm import backref
from sqlalchemy.orm import clear_mappers
from sqlalchemy.orm import configure_mappers
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import fixtures
class CompileTest(fixtures.MappedTest):
"""test various mapper compilation scenarios"""
def teardown_test(self):
clear_mappers()
def test_with_polymorphic(self):
metadata = MetaData()
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:
pass
class Employee:
pass
class Product:
pass
class OrderProduct:
pass
order_join = order.select().alias("pjoin")
self.mapper_registry.map_imperatively(
Order,
order,
with_polymorphic=("*", order_join),
polymorphic_on=order_join.c.type,
polymorphic_identity="order",
properties={
"orderproducts": relationship(
OrderProduct, lazy="select", backref="order"
)
},
)
self.mapper_registry.map_imperatively(
Product,
product,
properties={
"orderproducts": relationship(
OrderProduct, lazy="select", backref="product"
)
},
)
self.mapper_registry.map_imperatively(
Employee,
employee,
properties={
"orders": relationship(
Order, lazy="select", backref="employee"
)
},
)
self.mapper_registry.map_imperatively(OrderProduct, orderproduct)
configure_mappers()
def test_conflicting_backref_one(self):
"""test that conflicting backrefs raises an exception"""
metadata = MetaData()
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:
pass
class Product:
pass
class OrderProduct:
pass
order_join = order.select().alias("pjoin")
self.mapper_registry.map_imperatively(
Order,
order,
with_polymorphic=("*", order_join),
polymorphic_on=order_join.c.type,
polymorphic_identity="order",
properties={
"orderproducts": relationship(
OrderProduct, lazy="select", backref="product"
)
},
)
self.mapper_registry.map_imperatively(
Product,
product,
properties={
"orderproducts": relationship(
OrderProduct, lazy="select", backref="product"
)
},
)
self.mapper_registry.map_imperatively(OrderProduct, orderproduct)
assert_raises_message(
sa_exc.ArgumentError, "Error creating backref", configure_mappers
)
def test_misc_one(self, connection, metadata):
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(connection)
connection.execute(node_table.insert(), dict(node_id=1, node_index=5))
class Node:
pass
class NodeName:
pass
class Host:
pass
self.mapper_registry.map_imperatively(Node, node_table)
self.mapper_registry.map_imperatively(Host, host_table)
self.mapper_registry.map_imperatively(
NodeName,
node_name_table,
properties={
"node": relationship(Node, backref=backref("names")),
"host": relationship(Host),
},
)
sess = Session(connection)
assert sess.get(Node, 1).names == []
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:
pass
class B:
pass
self.mapper_registry.map_imperatively(
A, a, properties={"b": relationship(B, backref="a")}
)
self.mapper_registry.map_imperatively(
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:
pass
class B:
pass
class C(B):
pass
self.mapper_registry.map_imperatively(
A,
a,
properties={
"b": relationship(B, backref="a"),
"c": relationship(C, backref="a"),
},
)
self.mapper_registry.map_imperatively(B, b)
self.mapper_registry.map_imperatively(C, None, inherits=B)
assert_raises_message(
sa_exc.ArgumentError, "Error creating backref", configure_mappers
)