2
from sqlalchemy.testing import eq_, assert_raises, \
3
assert_raises_message, is_
4
from sqlalchemy.ext import declarative as decl
5
from sqlalchemy import exc
6
import sqlalchemy as sa
7
from sqlalchemy import testing
8
from sqlalchemy import MetaData, Integer, String, ForeignKey, \
9
ForeignKeyConstraint, Index
10
from sqlalchemy.testing.schema import Table, Column
11
from sqlalchemy.orm import relationship, create_session, class_mapper, \
12
joinedload, configure_mappers, backref, clear_mappers, \
13
deferred, column_property, composite,\
15
from sqlalchemy.testing import eq_
16
from sqlalchemy.util import classproperty
17
from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase, \
18
ConcreteBase, synonym_for
19
from sqlalchemy.testing import fixtures
20
from sqlalchemy.testing.util import gc_collect
24
class DeclarativeTestBase(fixtures.TestBase,
25
testing.AssertsExecutionResults,
26
testing.AssertsCompiledSQL):
27
__dialect__ = 'default'
30
Base = decl.declarative_base(testing.db)
35
Base.metadata.drop_all()
37
class DeclarativeTest(DeclarativeTestBase):
39
class User(Base, fixtures.ComparableEntity):
40
__tablename__ = 'users'
42
id = Column('id', Integer, primary_key=True,
43
test_needs_autoincrement=True)
44
name = Column('name', String(50))
45
addresses = relationship("Address", backref="user")
47
class Address(Base, fixtures.ComparableEntity):
48
__tablename__ = 'addresses'
50
id = Column(Integer, primary_key=True,
51
test_needs_autoincrement=True)
52
email = Column(String(50), key='_email')
53
user_id = Column('user_id', Integer, ForeignKey('users.id'),
56
Base.metadata.create_all()
58
eq_(Address.__table__.c['id'].name, 'id')
59
eq_(Address.__table__.c['_email'].name, 'email')
60
eq_(Address.__table__.c['_user_id'].name, 'user_id')
62
u1 = User(name='u1', addresses=[
66
sess = create_session()
71
eq_(sess.query(User).all(), [User(name='u1', addresses=[
76
a1 = sess.query(Address).filter(Address.email == 'two').one()
77
eq_(a1, Address(email='two'))
78
eq_(a1.user, User(name='u1'))
80
def test_no_table(self):
83
id = Column('id', Integer, primary_key=True)
85
assert_raises_message(sa.exc.InvalidRequestError,
86
'does not have a __table__', go)
88
def test_table_args_empty_dict(self):
91
__tablename__ = 'test'
92
id = Column(Integer, primary_key=True)
95
def test_table_args_empty_tuple(self):
98
__tablename__ = 'test'
99
id = Column(Integer, primary_key=True)
102
def test_cant_add_columns(self):
103
t = Table('t', Base.metadata, Column('id', Integer,
104
primary_key=True), Column('data', String))
109
foo = Column(Integer, primary_key=True)
111
# can't specify new columns not already in the table
113
assert_raises_message(sa.exc.ArgumentError,
114
"Can't add additional column 'foo' when "
115
"specifying __table__", go)
117
# regular re-mapping works tho
123
assert class_mapper(Bar).get_property('some_data').columns[0] \
126
def test_difficult_class(self):
127
"""test no getattr() errors with a customized class"""
129
# metaclass to mock the way zope.interface breaks getattr()
130
class BrokenMeta(type):
131
def __getattribute__(self, attr):
133
raise AttributeError, 'xyzzy'
135
return object.__getattribute__(self,attr)
137
# even though this class has an xyzzy attribute, getattr(cls,"xyzzy")
139
class BrokenParent(object):
140
__metaclass__ = BrokenMeta
143
# _as_declarative() inspects obj.__class__.__bases__
144
class User(BrokenParent,fixtures.ComparableEntity):
145
__tablename__ = 'users'
146
id = Column('id', Integer, primary_key=True,
147
test_needs_autoincrement=True)
148
name = Column('name', String(50))
150
decl.instrument_declarative(User,{},Base.metadata)
152
def test_reserved_identifiers(self):
155
__tablename__ = 'user1'
156
id = Column(Integer, primary_key=True)
157
metadata = Column(Integer)
161
__tablename__ = 'user2'
162
id = Column(Integer, primary_key=True)
163
metadata = relationship("Address")
165
for go in (go1, go2):
166
assert_raises_message(
167
exc.InvalidRequestError,
168
"Attribute name 'metadata' is reserved "
169
"for the MetaData instance when using a "
170
"declarative base class.",
174
def test_undefer_column_name(self):
175
# TODO: not sure if there was an explicit
176
# test for this elsewhere
177
foo = Column(Integer)
178
eq_(str(foo), '(no name)')
181
decl.base._undefer_column_name('foo', foo)
186
def test_recompile_on_othermapper(self):
187
"""declarative version of the same test in mappers.py"""
189
from sqlalchemy.orm import mapperlib
192
__tablename__ = 'users'
194
id = Column('id', Integer, primary_key=True)
195
name = Column('name', String(50))
198
__tablename__ = 'addresses'
200
id = Column('id', Integer, primary_key=True)
201
email = Column('email', String(50))
202
user_id = Column('user_id', Integer, ForeignKey('users.id'))
203
user = relationship("User", primaryjoin=user_id == User.id,
206
assert mapperlib._new_mappers is True
208
assert User.addresses
209
assert mapperlib._new_mappers is False
211
def test_string_dependency_resolution(self):
212
from sqlalchemy.sql import desc
214
class User(Base, fixtures.ComparableEntity):
216
__tablename__ = 'users'
217
id = Column(Integer, primary_key=True,
218
test_needs_autoincrement=True)
219
name = Column(String(50))
220
addresses = relationship('Address',
221
order_by='desc(Address.email)',
222
primaryjoin='User.id==Address.user_id',
223
foreign_keys='[Address.user_id]',
224
backref=backref('user',
225
primaryjoin='User.id==Address.user_id',
226
foreign_keys='[Address.user_id]'))
228
class Address(Base, fixtures.ComparableEntity):
230
__tablename__ = 'addresses'
231
id = Column(Integer, primary_key=True,
232
test_needs_autoincrement=True)
233
email = Column(String(50))
234
user_id = Column(Integer) # note no foreign key
236
Base.metadata.create_all()
237
sess = create_session()
238
u1 = User(name='ed', addresses=[Address(email='abc'),
239
Address(email='def'), Address(email='xyz')])
243
eq_(sess.query(User).filter(User.name == 'ed').one(),
244
User(name='ed', addresses=[Address(email='xyz'),
245
Address(email='def'), Address(email='abc')]))
247
class Foo(Base, fixtures.ComparableEntity):
249
__tablename__ = 'foo'
250
id = Column(Integer, primary_key=True)
251
rel = relationship('User',
252
primaryjoin='User.addresses==Foo.id')
254
assert_raises_message(exc.InvalidRequestError,
255
"'addresses' is not an instance of "
256
"ColumnProperty", configure_mappers)
258
def test_string_dependency_resolution_synonym(self):
259
from sqlalchemy.sql import desc
261
class User(Base, fixtures.ComparableEntity):
263
__tablename__ = 'users'
264
id = Column(Integer, primary_key=True,
265
test_needs_autoincrement=True)
266
name = Column(String(50))
268
Base.metadata.create_all()
269
sess = create_session()
274
eq_(sess.query(User).filter(User.name == 'ed').one(),
277
class Foo(Base, fixtures.ComparableEntity):
279
__tablename__ = 'foo'
280
id = Column(Integer, primary_key=True)
281
_user_id = Column(Integer)
282
rel = relationship('User',
284
foreign_keys=[User.id],
285
primaryjoin='Foo.user_id==User.id')
287
@synonym_for('_user_id')
296
def test_string_dependency_resolution_orm_descriptor(self):
297
from sqlalchemy.ext.hybrid import hybrid_property
300
__tablename__ = 'user'
301
id = Column(Integer, primary_key=True)
302
firstname = Column(String(50))
303
lastname = Column(String(50))
304
game_id = Column(Integer, ForeignKey('game.id'))
308
return self.firstname + " " + self.lastname
311
__tablename__ = 'game'
312
id = Column(Integer, primary_key=True)
313
name = Column(String(50))
314
users = relationship("User", order_by="User.fullname")
318
s.query(Game).options(joinedload(Game.users)),
319
"SELECT game.id AS game_id, game.name AS game_name, "
320
"user_1.id AS user_1_id, user_1.firstname AS user_1_firstname, "
321
"user_1.lastname AS user_1_lastname, "
322
"user_1.game_id AS user_1_game_id "
323
"FROM game LEFT OUTER JOIN \"user\" AS user_1 ON game.id = "
324
"user_1.game_id ORDER BY "
325
"user_1.firstname || :firstname_1 || user_1.lastname"
328
def test_string_dependency_resolution_no_table(self):
330
class User(Base, fixtures.ComparableEntity):
331
__tablename__ = 'users'
332
id = Column(Integer, primary_key=True,
333
test_needs_autoincrement=True)
334
name = Column(String(50))
336
class Bar(Base, fixtures.ComparableEntity):
337
__tablename__ = 'bar'
338
id = Column(Integer, primary_key=True)
339
rel = relationship('User',
340
primaryjoin='User.id==Bar.__table__.id')
342
assert_raises_message(exc.InvalidRequestError,
343
"does not have a mapped column named "
344
"'__table__'", configure_mappers)
346
def test_string_w_pj_annotations(self):
348
class User(Base, fixtures.ComparableEntity):
349
__tablename__ = 'users'
350
id = Column(Integer, primary_key=True,
351
test_needs_autoincrement=True)
352
name = Column(String(50))
353
class Address(Base, fixtures.ComparableEntity):
355
__tablename__ = 'addresses'
356
id = Column(Integer, primary_key=True,
357
test_needs_autoincrement=True)
358
email = Column(String(50))
359
user_id = Column(Integer)
360
user = relationship("User",
361
primaryjoin="remote(User.id)==foreign(Address.user_id)"
365
Address.user.property._join_condition.local_remote_pairs,
366
[(Address.__table__.c.user_id, User.__table__.c.id)]
369
def test_string_dependency_resolution_no_magic(self):
370
"""test that full tinkery expressions work as written"""
372
class User(Base, fixtures.ComparableEntity):
374
__tablename__ = 'users'
375
id = Column(Integer, primary_key=True)
376
addresses = relationship('Address',
377
primaryjoin='User.id==Address.user_id.prop.columns['
380
class Address(Base, fixtures.ComparableEntity):
382
__tablename__ = 'addresses'
383
id = Column(Integer, primary_key=True)
384
user_id = Column(Integer, ForeignKey('users.id'))
387
eq_(str(User.addresses.prop.primaryjoin),
388
'users.id = addresses.user_id')
390
def test_string_dependency_resolution_module_qualified(self):
391
class User(Base, fixtures.ComparableEntity):
393
__tablename__ = 'users'
394
id = Column(Integer, primary_key=True)
395
addresses = relationship('%s.Address' % __name__,
396
primaryjoin='%s.User.id==%s.Address.user_id.prop.columns['
397
'0]' % (__name__, __name__))
399
class Address(Base, fixtures.ComparableEntity):
401
__tablename__ = 'addresses'
402
id = Column(Integer, primary_key=True)
403
user_id = Column(Integer, ForeignKey('users.id'))
406
eq_(str(User.addresses.prop.primaryjoin),
407
'users.id = addresses.user_id')
409
def test_string_dependency_resolution_in_backref(self):
411
class User(Base, fixtures.ComparableEntity):
413
__tablename__ = 'users'
414
id = Column(Integer, primary_key=True)
415
name = Column(String(50))
416
addresses = relationship('Address',
417
primaryjoin='User.id==Address.user_id',
420
class Address(Base, fixtures.ComparableEntity):
422
__tablename__ = 'addresses'
423
id = Column(Integer, primary_key=True)
424
email = Column(String(50))
425
user_id = Column(Integer, ForeignKey('users.id'))
428
eq_(str(User.addresses.property.primaryjoin),
429
str(Address.user.property.primaryjoin))
431
def test_string_dependency_resolution_tables(self):
433
class User(Base, fixtures.ComparableEntity):
435
__tablename__ = 'users'
436
id = Column(Integer, primary_key=True)
437
name = Column(String(50))
438
props = relationship('Prop', secondary='user_to_prop',
439
primaryjoin='User.id==user_to_prop.c.u'
441
secondaryjoin='user_to_prop.c.prop_id='
442
'=Prop.id', backref='users')
444
class Prop(Base, fixtures.ComparableEntity):
446
__tablename__ = 'props'
447
id = Column(Integer, primary_key=True)
448
name = Column(String(50))
450
user_to_prop = Table('user_to_prop', Base.metadata,
451
Column('user_id', Integer,
452
ForeignKey('users.id')), Column('prop_id',
453
Integer, ForeignKey('props.id')))
455
assert class_mapper(User).get_property('props').secondary \
458
def test_string_dependency_resolution_schemas(self):
459
Base = decl.declarative_base()
463
__tablename__ = 'users'
464
__table_args__ = {'schema':'fooschema'}
466
id = Column(Integer, primary_key=True)
467
name = Column(String(50))
468
props = relationship('Prop', secondary='fooschema.user_to_prop',
469
primaryjoin='User.id==fooschema.user_to_prop.c.user_id',
470
secondaryjoin='fooschema.user_to_prop.c.prop_id==Prop.id',
475
__tablename__ = 'props'
476
__table_args__ = {'schema':'fooschema'}
478
id = Column(Integer, primary_key=True)
479
name = Column(String(50))
481
user_to_prop = Table('user_to_prop', Base.metadata,
482
Column('user_id', Integer, ForeignKey('fooschema.users.id')),
483
Column('prop_id',Integer, ForeignKey('fooschema.props.id')),
487
assert class_mapper(User).get_property('props').secondary \
490
def test_string_dependency_resolution_annotations(self):
491
Base = decl.declarative_base()
494
__tablename__ = 'parent'
495
id = Column(Integer, primary_key=True)
496
name = Column(String)
497
children = relationship("Child",
498
primaryjoin="Parent.name==remote(foreign(func.lower(Child.name_upper)))"
502
__tablename__ = 'child'
503
id = Column(Integer, primary_key=True)
504
name_upper = Column(String)
508
Parent.children.property._calculated_foreign_keys,
509
set([Child.name_upper.property.columns[0]])
512
def test_shared_class_registry(self):
514
Base1 = decl.declarative_base(testing.db, class_registry=reg)
515
Base2 = decl.declarative_base(testing.db, class_registry=reg)
519
id = Column(Integer, primary_key=True)
523
id = Column(Integer, primary_key=True)
524
aid = Column(Integer, ForeignKey(A.id))
525
as_ = relationship("A")
527
assert B.as_.property.mapper.class_ is A
529
def test_uncompiled_attributes_in_relationship(self):
531
class Address(Base, fixtures.ComparableEntity):
533
__tablename__ = 'addresses'
534
id = Column(Integer, primary_key=True,
535
test_needs_autoincrement=True)
536
email = Column(String(50))
537
user_id = Column(Integer, ForeignKey('users.id'))
539
class User(Base, fixtures.ComparableEntity):
541
__tablename__ = 'users'
542
id = Column(Integer, primary_key=True,
543
test_needs_autoincrement=True)
544
name = Column(String(50))
545
addresses = relationship('Address', order_by=Address.email,
546
foreign_keys=Address.user_id,
547
remote_side=Address.user_id)
549
# get the mapper for User. User mapper will compile,
550
# "addresses" relationship will call upon Address.user_id for
551
# its clause element. Address.user_id is a _CompileOnAttr,
552
# which then calls class_mapper(Address). But ! We're already
553
# "in compilation", but class_mapper(Address) needs to
554
# initialize regardless, or COA's assertion fails and things
555
# generally go downhill from there.
558
Base.metadata.create_all()
559
sess = create_session()
560
u1 = User(name='ed', addresses=[Address(email='abc'),
561
Address(email='xyz'), Address(email='def')])
565
eq_(sess.query(User).filter(User.name == 'ed').one(),
566
User(name='ed', addresses=[Address(email='abc'),
567
Address(email='def'), Address(email='xyz')]))
569
def test_nice_dependency_error(self):
573
__tablename__ = 'users'
574
id = Column('id', Integer, primary_key=True)
575
addresses = relationship('Address')
579
__tablename__ = 'addresses'
580
id = Column(Integer, primary_key=True)
581
foo = sa.orm.column_property(User.id == 5)
583
# this used to raise an error when accessing User.id but that's
584
# no longer the case since we got rid of _CompileOnAttr.
586
assert_raises(sa.exc.ArgumentError, configure_mappers)
588
def test_nice_dependency_error_works_with_hasattr(self):
592
__tablename__ = 'users'
593
id = Column('id', Integer, primary_key=True)
594
addresses = relationship('Address')
596
# hasattr() on a compile-loaded attribute
598
hasattr(User.addresses, 'property')
599
except exc.InvalidRequestError:
600
assert sa.util.compat.py32
602
# the exception is preserved. Remains the
603
# same through repeated calls.
605
assert_raises_message(sa.exc.InvalidRequestError,
606
"^One or more mappers failed to initialize - "
607
"can't proceed with initialization of other "
608
"mappers. Original exception was: When initializing.*",
611
def test_custom_base(self):
612
class MyBase(object):
615
Base = decl.declarative_base(cls=MyBase)
616
assert hasattr(Base, 'metadata')
617
assert Base().foobar() == "foobar"
619
def test_uses_get_on_class_col_fk(self):
625
__tablename__ = 'master'
626
id = Column(Integer, primary_key=True,
627
test_needs_autoincrement=True)
631
__tablename__ = 'detail'
632
id = Column(Integer, primary_key=True,
633
test_needs_autoincrement=True)
634
master_id = Column(None, ForeignKey(Master.id))
635
master = relationship(Master)
637
Base.metadata.create_all()
639
assert class_mapper(Detail).get_property('master'
642
d1 = Detail(master=m1)
643
sess = create_session()
647
d1 = sess.query(Detail).first()
648
m1 = sess.query(Master).first()
653
self.assert_sql_count(testing.db, go, 0)
655
def test_index_doesnt_compile(self):
657
__tablename__ = 'users'
658
id = Column('id', Integer, primary_key=True)
659
name = Column('name', String(50))
660
error = relationship("Address")
662
i = Index('my_index', User.name)
664
# compile fails due to the nonexistent Addresses relationship
665
assert_raises(sa.exc.InvalidRequestError, configure_mappers)
668
assert i in User.__table__.indexes
669
assert User.__table__.c.id not in set(i.columns)
670
assert User.__table__.c.name in set(i.columns)
673
Base.metadata.create_all()
675
def test_add_prop(self):
677
class User(Base, fixtures.ComparableEntity):
679
__tablename__ = 'users'
680
id = Column('id', Integer, primary_key=True,
681
test_needs_autoincrement=True)
683
User.name = Column('name', String(50))
684
User.addresses = relationship('Address', backref='user')
686
class Address(Base, fixtures.ComparableEntity):
688
__tablename__ = 'addresses'
689
id = Column(Integer, primary_key=True,
690
test_needs_autoincrement=True)
692
Address.email = Column(String(50), key='_email')
693
Address.user_id = Column('user_id', Integer,
694
ForeignKey('users.id'), key='_user_id')
695
Base.metadata.create_all()
696
eq_(Address.__table__.c['id'].name, 'id')
697
eq_(Address.__table__.c['_email'].name, 'email')
698
eq_(Address.__table__.c['_user_id'].name, 'user_id')
699
u1 = User(name='u1', addresses=[Address(email='one'),
700
Address(email='two')])
701
sess = create_session()
705
eq_(sess.query(User).all(), [User(name='u1',
706
addresses=[Address(email='one'), Address(email='two')])])
707
a1 = sess.query(Address).filter(Address.email == 'two').one()
708
eq_(a1, Address(email='two'))
709
eq_(a1.user, User(name='u1'))
711
def test_eager_order_by(self):
713
class Address(Base, fixtures.ComparableEntity):
715
__tablename__ = 'addresses'
716
id = Column('id', Integer, primary_key=True,
717
test_needs_autoincrement=True)
718
email = Column('email', String(50))
719
user_id = Column('user_id', Integer, ForeignKey('users.id'))
721
class User(Base, fixtures.ComparableEntity):
723
__tablename__ = 'users'
724
id = Column('id', Integer, primary_key=True,
725
test_needs_autoincrement=True)
726
name = Column('name', String(50))
727
addresses = relationship('Address', order_by=Address.email)
729
Base.metadata.create_all()
730
u1 = User(name='u1', addresses=[Address(email='two'),
731
Address(email='one')])
732
sess = create_session()
736
eq_(sess.query(User).options(joinedload(User.addresses)).all(),
737
[User(name='u1', addresses=[Address(email='one'),
738
Address(email='two')])])
740
def test_order_by_multi(self):
742
class Address(Base, fixtures.ComparableEntity):
744
__tablename__ = 'addresses'
745
id = Column('id', Integer, primary_key=True,
746
test_needs_autoincrement=True)
747
email = Column('email', String(50))
748
user_id = Column('user_id', Integer, ForeignKey('users.id'))
750
class User(Base, fixtures.ComparableEntity):
752
__tablename__ = 'users'
753
id = Column('id', Integer, primary_key=True,
754
test_needs_autoincrement=True)
755
name = Column('name', String(50))
756
addresses = relationship('Address',
757
order_by=(Address.email, Address.id))
759
Base.metadata.create_all()
760
u1 = User(name='u1', addresses=[Address(email='two'),
761
Address(email='one')])
762
sess = create_session()
766
u = sess.query(User).filter(User.name == 'u1').one()
769
def test_as_declarative(self):
771
class User(fixtures.ComparableEntity):
773
__tablename__ = 'users'
774
id = Column('id', Integer, primary_key=True,
775
test_needs_autoincrement=True)
776
name = Column('name', String(50))
777
addresses = relationship('Address', backref='user')
779
class Address(fixtures.ComparableEntity):
781
__tablename__ = 'addresses'
782
id = Column('id', Integer, primary_key=True,
783
test_needs_autoincrement=True)
784
email = Column('email', String(50))
785
user_id = Column('user_id', Integer, ForeignKey('users.id'))
788
decl.instrument_declarative(User, reg, Base.metadata)
789
decl.instrument_declarative(Address, reg, Base.metadata)
790
Base.metadata.create_all()
791
u1 = User(name='u1', addresses=[Address(email='one'),
792
Address(email='two')])
793
sess = create_session()
797
eq_(sess.query(User).all(), [User(name='u1',
798
addresses=[Address(email='one'), Address(email='two')])])
800
def test_custom_mapper_attribute(self):
802
def mymapper(cls, tbl, **kwargs):
803
m = sa.orm.mapper(cls, tbl, **kwargs)
807
base = decl.declarative_base()
810
__tablename__ = 'foo'
811
__mapper_cls__ = mymapper
812
id = Column(Integer, primary_key=True)
814
eq_(Foo.__mapper__.CHECK, True)
816
def test_custom_mapper_argument(self):
818
def mymapper(cls, tbl, **kwargs):
819
m = sa.orm.mapper(cls, tbl, **kwargs)
823
base = decl.declarative_base(mapper=mymapper)
826
__tablename__ = 'foo'
827
id = Column(Integer, primary_key=True)
829
eq_(Foo.__mapper__.CHECK, True)
831
@testing.emits_warning('Ignoring declarative-like tuple value of '
837
class User(Base, fixtures.ComparableEntity):
839
__tablename__ = 'users'
840
id = Column('id', Integer, primary_key=True),
841
name = Column('name', String(50))
845
assert_raises_message(sa.exc.ArgumentError,
846
'Mapper Mapper|User|users could not '
847
'assemble any primary key', define)
849
def test_table_args_no_dict(self):
853
__tablename__ = 'foo'
854
__table_args__ = ForeignKeyConstraint(['id'], ['foo.bar']),
855
id = Column('id', Integer, primary_key=True)
856
bar = Column('bar', Integer)
858
assert Foo1.__table__.c.id.references(Foo1.__table__.c.bar)
860
def test_table_args_type(self):
864
__tablename__ = 'foo'
865
__table_args__ = ForeignKeyConstraint(['id'], ['foo.id'
867
id = Column('id', Integer, primary_key=True)
868
assert_raises_message(sa.exc.ArgumentError,
869
'__table_args__ value must be a tuple, ', err)
871
def test_table_args_none(self):
875
__tablename__ = 'foo'
876
__table_args__ = None
877
id = Column('id', Integer, primary_key=True)
879
assert Foo2.__table__.kwargs == {}
881
def test_table_args_dict_format(self):
885
__tablename__ = 'foo'
886
__table_args__ = {'mysql_engine': 'InnoDB'}
887
id = Column('id', Integer, primary_key=True)
889
assert Foo2.__table__.kwargs['mysql_engine'] == 'InnoDB'
891
def test_table_args_tuple_format(self):
894
__tablename__ = 'foo'
895
__table_args__ = {'mysql_engine': 'InnoDB'}
896
id = Column('id', Integer, primary_key=True)
900
__tablename__ = 'bar'
901
__table_args__ = ForeignKeyConstraint(['id'], ['foo.id']), \
902
{'mysql_engine': 'InnoDB'}
903
id = Column('id', Integer, primary_key=True)
905
assert Bar.__table__.c.id.references(Foo2.__table__.c.id)
906
assert Bar.__table__.kwargs['mysql_engine'] == 'InnoDB'
908
def test_expression(self):
910
class User(Base, fixtures.ComparableEntity):
912
__tablename__ = 'users'
913
id = Column('id', Integer, primary_key=True,
914
test_needs_autoincrement=True)
915
name = Column('name', String(50))
916
addresses = relationship('Address', backref='user')
918
class Address(Base, fixtures.ComparableEntity):
920
__tablename__ = 'addresses'
921
id = Column('id', Integer, primary_key=True,
922
test_needs_autoincrement=True)
923
email = Column('email', String(50))
924
user_id = Column('user_id', Integer, ForeignKey('users.id'))
926
User.address_count = \
927
sa.orm.column_property(sa.select([sa.func.count(Address.id)]).
928
where(Address.user_id
929
== User.id).as_scalar())
930
Base.metadata.create_all()
931
u1 = User(name='u1', addresses=[Address(email='one'),
932
Address(email='two')])
933
sess = create_session()
937
eq_(sess.query(User).all(), [User(name='u1', address_count=2,
938
addresses=[Address(email='one'), Address(email='two')])])
940
def test_useless_declared_attr(self):
941
class Address(Base, fixtures.ComparableEntity):
943
__tablename__ = 'addresses'
944
id = Column('id', Integer, primary_key=True,
945
test_needs_autoincrement=True)
946
email = Column('email', String(50))
947
user_id = Column('user_id', Integer, ForeignKey('users.id'))
949
class User(Base, fixtures.ComparableEntity):
951
__tablename__ = 'users'
952
id = Column('id', Integer, primary_key=True,
953
test_needs_autoincrement=True)
954
name = Column('name', String(50))
955
addresses = relationship('Address', backref='user')
958
def address_count(cls):
959
# this doesn't really gain us anything. but if
960
# one is used, lets have it function as expected...
961
return sa.orm.column_property(sa.select([sa.func.count(Address.id)]).
962
where(Address.user_id == cls.id))
964
Base.metadata.create_all()
965
u1 = User(name='u1', addresses=[Address(email='one'),
966
Address(email='two')])
967
sess = create_session()
971
eq_(sess.query(User).all(), [User(name='u1', address_count=2,
972
addresses=[Address(email='one'), Address(email='two')])])
974
def test_declared_on_base_class(self):
976
__tablename__ = 'foo'
977
id = Column(Integer, primary_key=True)
980
return Column(Integer)
982
class MyClass(MyBase):
983
__tablename__ = 'bar'
984
id = Column(Integer, ForeignKey('foo.id'), primary_key=True)
986
# previously, the 'somecol' declared_attr would be ignored
987
# by the mapping and would remain unused. now we take
988
# it as part of MyBase.
990
assert 'somecol' in MyBase.__table__.c
991
assert 'somecol' not in MyClass.__table__.c
993
def test_column(self):
995
class User(Base, fixtures.ComparableEntity):
997
__tablename__ = 'users'
998
id = Column('id', Integer, primary_key=True,
999
test_needs_autoincrement=True)
1000
name = Column('name', String(50))
1002
User.a = Column('a', String(10))
1003
User.b = Column(String(10))
1004
Base.metadata.create_all()
1005
u1 = User(name='u1', a='a', b='b')
1007
eq_(User.a.get_history(u1), (['a'], (), ()))
1008
sess = create_session()
1012
eq_(sess.query(User).all(), [User(name='u1', a='a', b='b')])
1014
def test_column_properties(self):
1016
class Address(Base, fixtures.ComparableEntity):
1018
__tablename__ = 'addresses'
1019
id = Column(Integer, primary_key=True,
1020
test_needs_autoincrement=True)
1021
email = Column(String(50))
1022
user_id = Column(Integer, ForeignKey('users.id'))
1024
class User(Base, fixtures.ComparableEntity):
1026
__tablename__ = 'users'
1027
id = Column('id', Integer, primary_key=True,
1028
test_needs_autoincrement=True)
1029
name = Column('name', String(50))
1032
sa.orm.column_property(
1033
sa.select([sa.func.count(Address.id)],
1034
Address.user_id == id).as_scalar())
1035
addresses = relationship(Address)
1037
Base.metadata.create_all()
1038
u1 = User(name='u1', addresses=[Address(email='one'),
1039
Address(email='two')])
1040
sess = create_session()
1044
eq_(sess.query(User).all(), [User(name='u1', adr_count=2,
1045
addresses=[Address(email='one'), Address(email='two')])])
1047
def test_column_properties_2(self):
1049
class Address(Base, fixtures.ComparableEntity):
1051
__tablename__ = 'addresses'
1052
id = Column(Integer, primary_key=True)
1053
email = Column(String(50))
1054
user_id = Column(Integer, ForeignKey('users.id'))
1056
class User(Base, fixtures.ComparableEntity):
1058
__tablename__ = 'users'
1059
id = Column('id', Integer, primary_key=True)
1060
name = Column('name', String(50))
1062
# this is not "valid" but we want to test that Address.id
1063
# doesnt get stuck into user's table
1065
adr_count = Address.id
1067
eq_(set(User.__table__.c.keys()), set(['id', 'name']))
1068
eq_(set(Address.__table__.c.keys()), set(['id', 'email',
1071
def test_deferred(self):
1073
class User(Base, fixtures.ComparableEntity):
1075
__tablename__ = 'users'
1076
id = Column(Integer, primary_key=True,
1077
test_needs_autoincrement=True)
1078
name = sa.orm.deferred(Column(String(50)))
1080
Base.metadata.create_all()
1081
sess = create_session()
1082
sess.add(User(name='u1'))
1085
u1 = sess.query(User).filter(User.name == 'u1').one()
1086
assert 'name' not in u1.__dict__
1091
self.assert_sql_count(testing.db, go, 1)
1093
def test_composite_inline(self):
1094
class AddressComposite(fixtures.ComparableEntity):
1095
def __init__(self, street, state):
1096
self.street = street
1098
def __composite_values__(self):
1099
return [self.street, self.state]
1101
class User(Base, fixtures.ComparableEntity):
1102
__tablename__ = 'user'
1103
id = Column(Integer, primary_key=True,
1104
test_needs_autoincrement=True)
1105
address = composite(AddressComposite,
1106
Column('street', String(50)),
1107
Column('state', String(2)),
1110
Base.metadata.create_all()
1113
address=AddressComposite('123 anywhere street',
1118
sess.query(User).all(),
1119
[User(address=AddressComposite('123 anywhere street',
1123
def test_composite_separate(self):
1124
class AddressComposite(fixtures.ComparableEntity):
1125
def __init__(self, street, state):
1126
self.street = street
1128
def __composite_values__(self):
1129
return [self.street, self.state]
1131
class User(Base, fixtures.ComparableEntity):
1132
__tablename__ = 'user'
1133
id = Column(Integer, primary_key=True,
1134
test_needs_autoincrement=True)
1135
street = Column(String(50))
1136
state = Column(String(2))
1137
address = composite(AddressComposite,
1140
Base.metadata.create_all()
1143
address=AddressComposite('123 anywhere street',
1148
sess.query(User).all(),
1149
[User(address=AddressComposite('123 anywhere street',
1153
def test_mapping_to_join(self):
1154
users = Table('users', Base.metadata,
1155
Column('id', Integer, primary_key=True)
1157
addresses = Table('addresses', Base.metadata,
1158
Column('id', Integer, primary_key=True),
1159
Column('user_id', Integer, ForeignKey('users.id'))
1161
usersaddresses = sa.join(users, addresses, users.c.id
1162
== addresses.c.user_id)
1164
__table__ = usersaddresses
1165
__table_args__ = {'primary_key':[users.c.id]}
1167
# need to use column_property for now
1168
user_id = column_property(users.c.id, addresses.c.user_id)
1169
address_id = addresses.c.id
1171
assert User.__mapper__.get_property('user_id').columns[0] \
1173
assert User.__mapper__.get_property('user_id').columns[1] \
1174
is addresses.c.user_id
1176
def test_synonym_inline(self):
1178
class User(Base, fixtures.ComparableEntity):
1180
__tablename__ = 'users'
1181
id = Column('id', Integer, primary_key=True,
1182
test_needs_autoincrement=True)
1183
_name = Column('name', String(50))
1185
def _set_name(self, name):
1186
self._name = 'SOMENAME ' + name
1188
def _get_name(self):
1191
name = sa.orm.synonym('_name',
1192
descriptor=property(_get_name,
1195
Base.metadata.create_all()
1196
sess = create_session()
1197
u1 = User(name='someuser')
1198
eq_(u1.name, 'SOMENAME someuser')
1201
eq_(sess.query(User).filter(User.name == 'SOMENAME someuser'
1204
def test_synonym_no_descriptor(self):
1205
from sqlalchemy.orm.properties import ColumnProperty
1207
class CustomCompare(ColumnProperty.Comparator):
1211
def __eq__(self, other):
1212
return self.__clause_element__() == other + ' FOO'
1214
class User(Base, fixtures.ComparableEntity):
1216
__tablename__ = 'users'
1217
id = Column('id', Integer, primary_key=True,
1218
test_needs_autoincrement=True)
1219
_name = Column('name', String(50))
1220
name = sa.orm.synonym('_name',
1221
comparator_factory=CustomCompare)
1223
Base.metadata.create_all()
1224
sess = create_session()
1225
u1 = User(name='someuser FOO')
1228
eq_(sess.query(User).filter(User.name == 'someuser').one(), u1)
1230
def test_synonym_added(self):
1232
class User(Base, fixtures.ComparableEntity):
1234
__tablename__ = 'users'
1235
id = Column('id', Integer, primary_key=True,
1236
test_needs_autoincrement=True)
1237
_name = Column('name', String(50))
1239
def _set_name(self, name):
1240
self._name = 'SOMENAME ' + name
1242
def _get_name(self):
1245
name = property(_get_name, _set_name)
1247
User.name = sa.orm.synonym('_name', descriptor=User.name)
1248
Base.metadata.create_all()
1249
sess = create_session()
1250
u1 = User(name='someuser')
1251
eq_(u1.name, 'SOMENAME someuser')
1254
eq_(sess.query(User).filter(User.name == 'SOMENAME someuser'
1257
def test_reentrant_compile_via_foreignkey(self):
1259
class User(Base, fixtures.ComparableEntity):
1261
__tablename__ = 'users'
1262
id = Column('id', Integer, primary_key=True,
1263
test_needs_autoincrement=True)
1264
name = Column('name', String(50))
1265
addresses = relationship('Address', backref='user')
1267
class Address(Base, fixtures.ComparableEntity):
1269
__tablename__ = 'addresses'
1270
id = Column('id', Integer, primary_key=True,
1271
test_needs_autoincrement=True)
1272
email = Column('email', String(50))
1273
user_id = Column('user_id', Integer, ForeignKey(User.id))
1275
# previous versions would force a re-entrant mapper compile via
1276
# the User.id inside the ForeignKey but this is no longer the
1279
sa.orm.configure_mappers()
1280
eq_(str(list(Address.user_id.property.columns[0].foreign_keys)[0]),
1281
"ForeignKey('users.id')")
1282
Base.metadata.create_all()
1283
u1 = User(name='u1', addresses=[Address(email='one'),
1284
Address(email='two')])
1285
sess = create_session()
1289
eq_(sess.query(User).all(), [User(name='u1',
1290
addresses=[Address(email='one'), Address(email='two')])])
1292
def test_relationship_reference(self):
1294
class Address(Base, fixtures.ComparableEntity):
1296
__tablename__ = 'addresses'
1297
id = Column('id', Integer, primary_key=True,
1298
test_needs_autoincrement=True)
1299
email = Column('email', String(50))
1300
user_id = Column('user_id', Integer, ForeignKey('users.id'))
1302
class User(Base, fixtures.ComparableEntity):
1304
__tablename__ = 'users'
1305
id = Column('id', Integer, primary_key=True,
1306
test_needs_autoincrement=True)
1307
name = Column('name', String(50))
1308
addresses = relationship('Address', backref='user',
1309
primaryjoin=id == Address.user_id)
1311
User.address_count = \
1312
sa.orm.column_property(sa.select([sa.func.count(Address.id)]).
1313
where(Address.user_id
1314
== User.id).as_scalar())
1315
Base.metadata.create_all()
1316
u1 = User(name='u1', addresses=[Address(email='one'),
1317
Address(email='two')])
1318
sess = create_session()
1322
eq_(sess.query(User).all(), [User(name='u1', address_count=2,
1323
addresses=[Address(email='one'), Address(email='two')])])
1325
def test_pk_with_fk_init(self):
1329
__tablename__ = 'bar'
1330
id = sa.Column(sa.Integer, sa.ForeignKey('foo.id'),
1332
ex = sa.Column(sa.Integer, primary_key=True)
1336
__tablename__ = 'foo'
1337
id = sa.Column(sa.Integer, primary_key=True)
1338
bars = sa.orm.relationship(Bar)
1340
assert Bar.__mapper__.primary_key[0] is Bar.__table__.c.id
1341
assert Bar.__mapper__.primary_key[1] is Bar.__table__.c.ex
1343
def test_with_explicit_autoloaded(self):
1344
meta = MetaData(testing.db)
1345
t1 = Table('t1', meta, Column('id', String(50),
1346
primary_key=True, test_needs_autoincrement=True),
1347
Column('data', String(50)))
1353
__table__ = Table('t1', Base.metadata, autoload=True)
1355
sess = create_session()
1356
m = MyObj(id='someid', data='somedata')
1359
eq_(t1.select().execute().fetchall(), [('someid', 'somedata'
1364
def test_synonym_for(self):
1366
class User(Base, fixtures.ComparableEntity):
1368
__tablename__ = 'users'
1369
id = Column('id', Integer, primary_key=True,
1370
test_needs_autoincrement=True)
1371
name = Column('name', String(50))
1373
@decl.synonym_for('name')
1378
Base.metadata.create_all()
1379
sess = create_session()
1380
u1 = User(name='someuser')
1381
eq_(u1.name, 'someuser')
1382
eq_(u1.namesyn, 'someuser')
1385
rt = sess.query(User).filter(User.namesyn == 'someuser').one()
1388
def test_comparable_using(self):
1390
class NameComparator(sa.orm.PropComparator):
1393
def upperself(self):
1394
cls = self.prop.parent.class_
1395
col = getattr(cls, 'name')
1396
return sa.func.upper(col)
1404
return op(self.upperself, other, **kw)
1406
class User(Base, fixtures.ComparableEntity):
1408
__tablename__ = 'users'
1409
id = Column('id', Integer, primary_key=True,
1410
test_needs_autoincrement=True)
1411
name = Column('name', String(50))
1413
@decl.comparable_using(NameComparator)
1416
return self.name is not None and self.name.upper() \
1419
Base.metadata.create_all()
1420
sess = create_session()
1421
u1 = User(name='someuser')
1422
eq_(u1.name, 'someuser', u1.name)
1423
eq_(u1.uc_name, 'SOMEUSER', u1.uc_name)
1427
rt = sess.query(User).filter(User.uc_name == 'SOMEUSER').one()
1430
rt = sess.query(User).filter(User.uc_name.startswith('SOMEUSE'
1434
def test_duplicate_classes_in_base(self):
1438
id = Column(Integer, primary_key=True)
1440
assert_raises_message(
1442
"This declarative base already contains a class with ",
1443
lambda: type(Base)("Test", (Base,), dict(
1445
id=Column(Integer, primary_key=True)
1451
def _produce_test(inline, stringbased):
1453
class ExplicitJoinTest(fixtures.MappedTest):
1456
def define_tables(cls, metadata):
1457
global User, Address
1458
Base = decl.declarative_base(metadata=metadata)
1460
class User(Base, fixtures.ComparableEntity):
1462
__tablename__ = 'users'
1463
id = Column(Integer, primary_key=True,
1464
test_needs_autoincrement=True)
1465
name = Column(String(50))
1467
class Address(Base, fixtures.ComparableEntity):
1469
__tablename__ = 'addresses'
1470
id = Column(Integer, primary_key=True,
1471
test_needs_autoincrement=True)
1472
email = Column(String(50))
1473
user_id = Column(Integer, ForeignKey('users.id'))
1476
user = relationship('User',
1477
primaryjoin='User.id==Address.user_id',
1478
backref='addresses')
1480
user = relationship(User, primaryjoin=User.id
1481
== user_id, backref='addresses')
1486
Address.user = relationship('User',
1487
primaryjoin='User.id==Address.user_id',
1488
backref='addresses')
1490
Address.user = relationship(User,
1491
primaryjoin=User.id == Address.user_id,
1492
backref='addresses')
1495
def insert_data(cls):
1496
params = [dict(zip(('id', 'name'), column_values))
1497
for column_values in [(7, 'jack'), (8, 'ed'), (9,
1498
'fred'), (10, 'chuck')]]
1499
User.__table__.insert().execute(params)
1500
Address.__table__.insert().execute([dict(zip(('id',
1501
'user_id', 'email'), column_values))
1502
for column_values in [(1, 7, 'jack@bean.com'), (2,
1503
8, 'ed@wood.com'), (3, 8, 'ed@bettyboop.com'), (4,
1504
8, 'ed@lala.com'), (5, 9, 'fred@fred.com')]])
1506
def test_aliased_join(self):
1508
# this query will screw up if the aliasing enabled in
1509
# query.join() gets applied to the right half of the join
1510
# condition inside the any(). the join condition inside of
1511
# any() comes from the "primaryjoin" of the relationship,
1512
# and should not be annotated with _orm_adapt.
1513
# PropertyLoader.Comparator will annotate the left side with
1514
# _orm_adapt, though.
1516
sess = create_session()
1517
eq_(sess.query(User).join(User.addresses,
1518
aliased=True).filter(Address.email == 'ed@wood.com'
1519
).filter(User.addresses.any(Address.email
1520
== 'jack@bean.com')).all(), [])
1522
ExplicitJoinTest.__name__ = 'ExplicitJoinTest%s%s' % (inline
1523
and 'Inline' or 'Separate', stringbased and 'String'
1525
return ExplicitJoinTest
1527
for inline in True, False:
1528
for stringbased in True, False:
1529
testclass = _produce_test(inline, stringbased)
1530
exec '%s = testclass' % testclass.__name__