mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-28 11:35:19 -04:00
20cdc64588
become an externally usable package but still remains within the main sqlalchemy parent package. in this system, we use kind of an ugly hack to get the noseplugin imported outside of the "sqlalchemy" package, while still making it available within sqlalchemy for usage by third party libraries.
261 lines
7.6 KiB
Python
261 lines
7.6 KiB
Python
from sqlalchemy.testing import eq_, assert_raises, \
|
|
assert_raises_message
|
|
from sqlalchemy import exc as sa_exc, util, Integer, String, ForeignKey
|
|
from sqlalchemy.orm import exc as orm_exc, mapper, relationship, \
|
|
sessionmaker, Session
|
|
from sqlalchemy import testing
|
|
from sqlalchemy.testing import profiling
|
|
from sqlalchemy.testing import fixtures
|
|
from sqlalchemy.testing.schema import Table, Column
|
|
import sys
|
|
|
|
class MergeTest(fixtures.MappedTest):
|
|
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
Table('parent', metadata, Column('id', Integer,
|
|
primary_key=True,
|
|
test_needs_autoincrement=True), Column('data',
|
|
String(20)))
|
|
Table('child', metadata, Column('id', Integer,
|
|
primary_key=True, test_needs_autoincrement=True),
|
|
Column('data', String(20)), Column('parent_id',
|
|
Integer, ForeignKey('parent.id'), nullable=False))
|
|
|
|
@classmethod
|
|
def setup_classes(cls):
|
|
class Parent(cls.Basic):
|
|
pass
|
|
|
|
class Child(cls.Basic):
|
|
pass
|
|
|
|
@classmethod
|
|
def setup_mappers(cls):
|
|
Child, Parent, parent, child = (cls.classes.Child,
|
|
cls.classes.Parent,
|
|
cls.tables.parent,
|
|
cls.tables.child)
|
|
|
|
mapper(Parent, parent, properties={'children':
|
|
relationship(Child, backref='parent')})
|
|
mapper(Child, child)
|
|
|
|
@classmethod
|
|
def insert_data(cls):
|
|
parent, child = cls.tables.parent, cls.tables.child
|
|
|
|
parent.insert().execute({'id': 1, 'data': 'p1'})
|
|
child.insert().execute({'id': 1, 'data': 'p1c1', 'parent_id': 1})
|
|
|
|
def test_merge_no_load(self):
|
|
Parent = self.classes.Parent
|
|
|
|
sess = sessionmaker()()
|
|
sess2 = sessionmaker()()
|
|
p1 = sess.query(Parent).get(1)
|
|
p1.children
|
|
|
|
# down from 185 on this this is a small slice of a usually
|
|
# bigger operation so using a small variance
|
|
|
|
@profiling.function_call_count(variance=0.10)
|
|
def go1():
|
|
return sess2.merge(p1, load=False)
|
|
p2 = go1()
|
|
|
|
# third call, merge object already present. almost no calls.
|
|
|
|
@profiling.function_call_count(variance=0.10)
|
|
def go2():
|
|
return sess2.merge(p2, load=False)
|
|
go2()
|
|
|
|
def test_merge_load(self):
|
|
Parent = self.classes.Parent
|
|
|
|
sess = sessionmaker()()
|
|
sess2 = sessionmaker()()
|
|
p1 = sess.query(Parent).get(1)
|
|
p1.children
|
|
|
|
# preloading of collection took this down from 1728 to 1192
|
|
# using sqlite3 the C extension took it back up to approx. 1257
|
|
# (py2.6)
|
|
|
|
@profiling.function_call_count()
|
|
def go():
|
|
p2 = sess2.merge(p1)
|
|
go()
|
|
|
|
# one more time, count the SQL
|
|
|
|
def go2():
|
|
p2 = sess2.merge(p1)
|
|
sess2 = sessionmaker(testing.db)()
|
|
self.assert_sql_count(testing.db, go2, 2)
|
|
|
|
class LoadManyToOneFromIdentityTest(fixtures.MappedTest):
|
|
"""test overhead associated with many-to-one fetches.
|
|
|
|
Prior to the refactor of LoadLazyAttribute and
|
|
query._get(), the load from identity map took 2x
|
|
as many calls (65K calls here instead of around 33K)
|
|
to load 1000 related objects from the identity map.
|
|
|
|
"""
|
|
|
|
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
Table('parent', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('data', String(20)),
|
|
Column('child_id', Integer, ForeignKey('child.id'))
|
|
)
|
|
|
|
Table('child', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('data', String(20))
|
|
)
|
|
|
|
@classmethod
|
|
def setup_classes(cls):
|
|
class Parent(cls.Basic):
|
|
pass
|
|
|
|
class Child(cls.Basic):
|
|
pass
|
|
|
|
@classmethod
|
|
def setup_mappers(cls):
|
|
Child, Parent, parent, child = (cls.classes.Child,
|
|
cls.classes.Parent,
|
|
cls.tables.parent,
|
|
cls.tables.child)
|
|
|
|
mapper(Parent, parent, properties={
|
|
'child': relationship(Child)})
|
|
mapper(Child, child)
|
|
|
|
@classmethod
|
|
def insert_data(cls):
|
|
parent, child = cls.tables.parent, cls.tables.child
|
|
|
|
child.insert().execute([
|
|
{'id':i, 'data':'c%d' % i}
|
|
for i in xrange(1, 251)
|
|
])
|
|
parent.insert().execute([
|
|
{
|
|
'id':i,
|
|
'data':'p%dc%d' % (i, (i % 250) + 1),
|
|
'child_id':(i % 250) + 1
|
|
}
|
|
for i in xrange(1, 1000)
|
|
])
|
|
|
|
def test_many_to_one_load_no_identity(self):
|
|
Parent = self.classes.Parent
|
|
|
|
sess = Session()
|
|
parents = sess.query(Parent).all()
|
|
|
|
|
|
@profiling.function_call_count(variance=.2)
|
|
def go():
|
|
for p in parents:
|
|
p.child
|
|
go()
|
|
|
|
def test_many_to_one_load_identity(self):
|
|
Parent, Child = self.classes.Parent, self.classes.Child
|
|
|
|
sess = Session()
|
|
parents = sess.query(Parent).all()
|
|
children = sess.query(Child).all()
|
|
|
|
@profiling.function_call_count()
|
|
def go():
|
|
for p in parents:
|
|
p.child
|
|
go()
|
|
|
|
class MergeBackrefsTest(fixtures.MappedTest):
|
|
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
Table('a', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('c_id', Integer, ForeignKey('c.id'))
|
|
)
|
|
Table('b', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('a_id', Integer, ForeignKey('a.id'))
|
|
)
|
|
Table('c', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
)
|
|
Table('d', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('a_id', Integer, ForeignKey('a.id'))
|
|
)
|
|
|
|
@classmethod
|
|
def setup_classes(cls):
|
|
class A(cls.Basic):
|
|
pass
|
|
class B(cls.Basic):
|
|
pass
|
|
class C(cls.Basic):
|
|
pass
|
|
class D(cls.Basic):
|
|
pass
|
|
|
|
@classmethod
|
|
def setup_mappers(cls):
|
|
A, B, C, D = cls.classes.A, cls.classes.B, \
|
|
cls.classes.C, cls.classes.D
|
|
a, b, c, d = cls.tables.a, cls.tables.b, \
|
|
cls.tables.c, cls.tables.d
|
|
mapper(A, a, properties={
|
|
'bs': relationship(B, backref='a'),
|
|
'c': relationship(C, backref='as'),
|
|
'ds': relationship(D, backref='a'),
|
|
})
|
|
mapper(B, b)
|
|
mapper(C, c)
|
|
mapper(D, d)
|
|
|
|
@classmethod
|
|
def insert_data(cls):
|
|
A, B, C, D = cls.classes.A, cls.classes.B, \
|
|
cls.classes.C, cls.classes.D
|
|
s = Session()
|
|
s.add_all([
|
|
A(id=i,
|
|
bs=[B(id=(i * 5) + j) for j in xrange(1, 5)],
|
|
c=C(id=i),
|
|
ds=[D(id=(i * 5) + j) for j in xrange(1, 5)]
|
|
)
|
|
for i in xrange(1, 5)
|
|
])
|
|
s.commit()
|
|
|
|
@profiling.function_call_count(variance=.10)
|
|
def test_merge_pending_with_all_pks(self):
|
|
A, B, C, D = self.classes.A, self.classes.B, \
|
|
self.classes.C, self.classes.D
|
|
s = Session()
|
|
for a in [
|
|
A(id=i,
|
|
bs=[B(id=(i * 5) + j) for j in xrange(1, 5)],
|
|
c=C(id=i),
|
|
ds=[D(id=(i * 5) + j) for j in xrange(1, 5)]
|
|
)
|
|
for i in xrange(1, 5)
|
|
]:
|
|
s.merge(a)
|
|
|
|
|