Show
Ignore:
Timestamp:
08/21/08 17:32:31 (5 years ago)
Author:
ged
Message:

New features:
- The local_colname and remote_colname arguments on ManyToMany relationships

can now also be used to set custom names for the ManyToMany table columns.
This effectively replace the column_format on ManyToMany relationships which
is now deprecated. Change based on a patch from Diez B. Roggisch.

- Added (or rather fixed and documented) a "table" argument on ManyToMany

relationships to allow using a manually-defined Table (closes #44).

- Added a "schema" argument on ManyToMany relationship to be able to create the

ManyToMany table in a custom schema and not necessarily the same schema as
the table of the "source" entity (patch from Diez B. Roggisch).

Changes:
- Renamed remote_side and local_side ManyToMany arguments to remote_colname and

local_colname respectively to not collide with the remote_side argument
provided by SA (it doesn't make much sense on ManyToMany relationships but
still).

Bug fixes:
- Changed slightly the algorithm to generate the name of the table for

bidirectional self-referential ManyToMany relationships so that it doesn't
depend on the order of declaration of each side (closes #19). If you are
upgrading an application with existing data from an earlier version of
Elixir, you are STRONGLY ADVISED to read the upgrade notes!
=============================
TEMPORARY BUT IMPORTANT NOTE:
=============================
For now it is even worse: the table works but the relationship's meaning is
reversed. Will be fixed before 0.7 ships (see ticket #69).
=============================

- Added missing documentation for the "filter" argument on OneToMany

relationships

Not logged in CHANGES:
- bumped version
- added a few tests
- completed/fixed the API doc a bit
- added some comments in the code so that I remember why things are done this

way.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • elixir/trunk/tests/test_m2m.py

    r349 r397  
    121121    def test_selfref(self): 
    122122        class Person(Entity): 
     123            using_options(shortnames=True) 
    123124            name = Field(String(30)) 
    124125 
    125126            friends = ManyToMany('Person') 
     127 
     128        setup_all(True) 
     129 
     130        barney = Person(name="Barney") 
     131        homer = Person(name="Homer", friends=[barney]) 
     132        barney.friends.append(homer) 
     133 
     134        session.commit() 
     135        session.clear() 
     136 
     137        homer = Person.get_by(name="Homer") 
     138        barney = Person.get_by(name="Barney") 
     139 
     140        assert homer in barney.friends 
     141        assert barney in homer.friends 
     142 
     143    def test_bidirectional_selfref(self): 
     144        class Person(Entity): 
     145            using_options(shortnames=True) 
     146            name = Field(String(30)) 
     147 
     148            friends = ManyToMany('Person') 
     149            is_friend_of = ManyToMany('Person') 
    126150 
    127151        setup_all(True) 
     
    170194        assert not a3.bs 
    171195 
     196    def test_local_and_remote_colnames(self): 
     197        class A(Entity): 
     198            using_options(shortnames=True) 
     199            key1 = Field(Integer, primary_key=True, autoincrement=False) 
     200            key2 = Field(String(40), primary_key=True) 
     201 
     202            bs_ = ManyToMany('B', local_colname=['foo', 'bar'], 
     203                                  remote_colname="baz") 
     204 
     205        class B(Entity): 
     206            using_options(shortnames=True) 
     207            name = Field(String(60)) 
     208            as_ = ManyToMany('A', remote_colname=['foo', 'bar'], 
     209                                  local_colname="baz") 
     210 
     211        setup_all(True) 
     212 
     213        b1 = B(name='b1', as_=[A(key1=10, key2='a1')]) 
     214 
     215        session.commit() 
     216        session.clear() 
     217 
     218        a = A.query.one() 
     219        b = B.query.one() 
     220 
     221        assert a in b.as_ 
     222        assert b in a.bs_ 
     223 
     224    def test_manual_table_auto_joins(self): 
     225        from sqlalchemy import Table, Column, ForeignKey, ForeignKeyConstraint 
     226 
     227        a_b = Table('a_b', metadata, 
     228                    Column('a_key1', None), 
     229                    Column('a_key2', None), 
     230                    Column('b_id', None, ForeignKey('b.id')), 
     231                    ForeignKeyConstraint(['a_key1', 'a_key2'], 
     232                                         ['a.key1', 'a.key2'])) 
     233 
     234        class A(Entity): 
     235            using_options(shortnames=True) 
     236            key1 = Field(Integer, primary_key=True, autoincrement=False) 
     237            key2 = Field(String(40), primary_key=True) 
     238 
     239            bs_ = ManyToMany('B', table=a_b) 
     240 
     241        class B(Entity): 
     242            using_options(shortnames=True) 
     243            name = Field(String(60)) 
     244            as_ = ManyToMany('A', table=a_b) 
     245 
     246        setup_all(True) 
     247 
     248        b1 = B(name='b1', as_=[A(key1=10, key2='a1')]) 
     249 
     250        session.commit() 
     251        session.clear() 
     252 
     253        a = A.query.one() 
     254        b = B.query.one() 
     255 
     256        assert a in b.as_ 
     257        assert b in a.bs_ 
     258 
     259    def test_manual_table_manual_joins(self): 
     260        from sqlalchemy import Table, Column, ForeignKey, \ 
     261                               ForeignKeyConstraint, and_ 
     262 
     263        a_b = Table('a_b', metadata, 
     264                    Column('a_key1', Integer), 
     265                    Column('a_key2', String(40)), 
     266                    Column('b_id', String(60))) 
     267 
     268        class A(Entity): 
     269            using_options(shortnames=True) 
     270            key1 = Field(Integer, primary_key=True, autoincrement=False) 
     271            key2 = Field(String(40), primary_key=True) 
     272 
     273            bs_ = ManyToMany('B', table=a_b, 
     274                             primaryjoin=lambda: and_(A.key1 == a_b.c.a_key1, 
     275                                                      A.key2 == a_b.c.a_key2), 
     276                             secondaryjoin=lambda: B.id == a_b.c.b_id, 
     277                             foreign_keys=[a_b.c.a_key1, a_b.c.a_key2, 
     278                                 a_b.c.b_id]) 
     279 
     280        class B(Entity): 
     281            using_options(shortnames=True) 
     282            name = Field(String(60)) 
     283 
     284        setup_all(True) 
     285 
     286        a1 = A(key1=10, key2='a1', bs_=[B(name='b1')]) 
     287 
     288        session.commit() 
     289        session.clear() 
     290 
     291        a = A.query.one() 
     292        b = B.query.one() 
     293 
     294        assert b in a.bs_