| 1 | """ |
|---|
| 2 | test one to many relationships |
|---|
| 3 | """ |
|---|
| 4 | |
|---|
| 5 | from elixir import * |
|---|
| 6 | from sqlalchemy import and_ |
|---|
| 7 | from sqlalchemy.ext.orderinglist import ordering_list |
|---|
| 8 | |
|---|
| 9 | def setup(): |
|---|
| 10 | metadata.bind = 'sqlite://' |
|---|
| 11 | |
|---|
| 12 | class TestOneToMany(object): |
|---|
| 13 | def teardown(self): |
|---|
| 14 | cleanup_all(True) |
|---|
| 15 | |
|---|
| 16 | def test_simple(self): |
|---|
| 17 | class A(Entity): |
|---|
| 18 | name = Field(String(60)) |
|---|
| 19 | bs = OneToMany('B') |
|---|
| 20 | |
|---|
| 21 | class B(Entity): |
|---|
| 22 | name = Field(String(60)) |
|---|
| 23 | a = ManyToOne('A') |
|---|
| 24 | |
|---|
| 25 | setup_all(True) |
|---|
| 26 | |
|---|
| 27 | a1 = A(name='a1') |
|---|
| 28 | b1 = B(name='b1', a=a1) |
|---|
| 29 | |
|---|
| 30 | # does it work before a commit? (does the backref work?) |
|---|
| 31 | assert b1 in a1.bs |
|---|
| 32 | |
|---|
| 33 | session.commit() |
|---|
| 34 | session.expunge_all() |
|---|
| 35 | |
|---|
| 36 | b = B.query.one() |
|---|
| 37 | a = b.a |
|---|
| 38 | |
|---|
| 39 | assert b in a.bs |
|---|
| 40 | |
|---|
| 41 | def test_selfref(self): |
|---|
| 42 | class Person(Entity): |
|---|
| 43 | name = Field(String(30)) |
|---|
| 44 | |
|---|
| 45 | father = ManyToOne('Person', inverse='children') |
|---|
| 46 | children = OneToMany('Person', inverse='father') |
|---|
| 47 | |
|---|
| 48 | setup_all(True) |
|---|
| 49 | |
|---|
| 50 | grampa = Person(name="Abe") |
|---|
| 51 | homer = Person(name="Homer") |
|---|
| 52 | bart = Person(name="Bart") |
|---|
| 53 | lisa = Person(name="Lisa") |
|---|
| 54 | |
|---|
| 55 | grampa.children.append(homer) |
|---|
| 56 | homer.children.append(bart) |
|---|
| 57 | lisa.father = homer |
|---|
| 58 | |
|---|
| 59 | session.commit() |
|---|
| 60 | session.expunge_all() |
|---|
| 61 | |
|---|
| 62 | p = Person.get_by(name="Homer") |
|---|
| 63 | |
|---|
| 64 | assert p in p.father.children |
|---|
| 65 | assert p.father is Person.get_by(name="Abe") |
|---|
| 66 | assert p is Person.get_by(name="Lisa").father |
|---|
| 67 | |
|---|
| 68 | def test_multiple_selfref(self): |
|---|
| 69 | # define a self-referential table with several relations |
|---|
| 70 | |
|---|
| 71 | class TreeNode(Entity): |
|---|
| 72 | using_options(order_by='name') |
|---|
| 73 | name = Field(String(50), required=True) |
|---|
| 74 | |
|---|
| 75 | parent = ManyToOne('TreeNode') |
|---|
| 76 | children = OneToMany('TreeNode', inverse='parent') |
|---|
| 77 | root = ManyToOne('TreeNode') |
|---|
| 78 | |
|---|
| 79 | setup_all(True) |
|---|
| 80 | |
|---|
| 81 | root = TreeNode(name='rootnode') |
|---|
| 82 | root.children.append(TreeNode(name='node1', root=root)) |
|---|
| 83 | node2 = TreeNode(name='node2', root=root) |
|---|
| 84 | node2.children.append(TreeNode(name='subnode1', root=root)) |
|---|
| 85 | node2.children.append(TreeNode(name='subnode2', root=root)) |
|---|
| 86 | root.children.append(node2) |
|---|
| 87 | root.children.append(TreeNode(name='node3', root=root)) |
|---|
| 88 | |
|---|
| 89 | session.commit() |
|---|
| 90 | session.expunge_all() |
|---|
| 91 | |
|---|
| 92 | root = TreeNode.get_by(name='rootnode') |
|---|
| 93 | sub2 = TreeNode.get_by(name='subnode2') |
|---|
| 94 | assert sub2 in root.children[1].children |
|---|
| 95 | assert sub2.root == root |
|---|
| 96 | |
|---|
| 97 | def test_viewonly(self): |
|---|
| 98 | class User(Entity): |
|---|
| 99 | name = Field(String(50)) |
|---|
| 100 | boston_addresses = OneToMany('Address', primaryjoin=lambda: |
|---|
| 101 | and_(Address.user_id == User.id, Address.city == u'Boston'), |
|---|
| 102 | viewonly=True |
|---|
| 103 | ) |
|---|
| 104 | addresses = OneToMany('Address') |
|---|
| 105 | |
|---|
| 106 | class Address(Entity): |
|---|
| 107 | user = ManyToOne('User') |
|---|
| 108 | street = Field(Unicode(255)) |
|---|
| 109 | city = Field(Unicode(255)) |
|---|
| 110 | |
|---|
| 111 | setup_all(True) |
|---|
| 112 | |
|---|
| 113 | user = User(name="u1", |
|---|
| 114 | addresses=[Address(street=u"Queen Astrid Avenue, 32", |
|---|
| 115 | city=u"Brussels"), |
|---|
| 116 | Address(street=u"Cambridge Street, 5", |
|---|
| 117 | city=u"Boston")]) |
|---|
| 118 | |
|---|
| 119 | session.commit() |
|---|
| 120 | session.expunge_all() |
|---|
| 121 | |
|---|
| 122 | user = User.get(1) |
|---|
| 123 | assert len(user.addresses) == 2 |
|---|
| 124 | assert len(user.boston_addresses) == 1 |
|---|
| 125 | assert "Cambridge" in user.boston_addresses[0].street |
|---|
| 126 | |
|---|
| 127 | def test_filter_func(self): |
|---|
| 128 | class User(Entity): |
|---|
| 129 | name = Field(String(50)) |
|---|
| 130 | boston_addresses = OneToMany('Address', filter=lambda c: |
|---|
| 131 | c.city == u'Boston') |
|---|
| 132 | addresses = OneToMany('Address') |
|---|
| 133 | |
|---|
| 134 | class Address(Entity): |
|---|
| 135 | user = ManyToOne('User') |
|---|
| 136 | street = Field(Unicode(255)) |
|---|
| 137 | city = Field(Unicode(255)) |
|---|
| 138 | |
|---|
| 139 | setup_all(True) |
|---|
| 140 | |
|---|
| 141 | user = User(name="u1", |
|---|
| 142 | addresses=[Address(street=u"Queen Astrid Avenue, 32", |
|---|
| 143 | city=u"Brussels"), |
|---|
| 144 | Address(street=u"Cambridge Street, 5", |
|---|
| 145 | city=u"Boston")]) |
|---|
| 146 | |
|---|
| 147 | session.commit() |
|---|
| 148 | session.expunge_all() |
|---|
| 149 | |
|---|
| 150 | user = User.get(1) |
|---|
| 151 | assert len(user.addresses) == 2 |
|---|
| 152 | assert len(user.boston_addresses) == 1 |
|---|
| 153 | assert "Cambridge" in user.boston_addresses[0].street |
|---|
| 154 | |
|---|
| 155 | def test_ordering_list(self): |
|---|
| 156 | class User(Entity): |
|---|
| 157 | name = Field(String(50)) |
|---|
| 158 | blurbs = OneToMany('Blurb', |
|---|
| 159 | collection_class=ordering_list('position'), |
|---|
| 160 | order_by='position') |
|---|
| 161 | |
|---|
| 162 | class Blurb(Entity): |
|---|
| 163 | user = ManyToOne('User') |
|---|
| 164 | position = Field(Integer) |
|---|
| 165 | text = Field(Unicode(255)) |
|---|
| 166 | |
|---|
| 167 | setup_all(True) |
|---|
| 168 | |
|---|
| 169 | user = User(name="u1", |
|---|
| 170 | blurbs=[Blurb(text=u'zero'), |
|---|
| 171 | Blurb(text=u'one'), |
|---|
| 172 | Blurb(text=u'two')]) |
|---|
| 173 | |
|---|
| 174 | session.commit() |
|---|
| 175 | session.expunge_all() |
|---|
| 176 | |
|---|
| 177 | user = User.get(1) |
|---|
| 178 | assert len(user.blurbs) == 3 |
|---|
| 179 | user.blurbs.insert(1, Blurb(text=u'new one')) |
|---|
| 180 | assert user.blurbs[2].text == "one" |
|---|
| 181 | assert user.blurbs[2].position == 2 |
|---|
| 182 | assert user.blurbs[3].text == "two" |
|---|
| 183 | assert user.blurbs[3].position == 3 |
|---|
| 184 | |
|---|
| 185 | # def test_manual_join_no_inverse(self): |
|---|
| 186 | # class A(Entity): |
|---|
| 187 | # name = Field(String(60)) |
|---|
| 188 | # bs = OneToMany('B') |
|---|
| 189 | # |
|---|
| 190 | # class B(Entity): |
|---|
| 191 | # name = Field(String(60)) |
|---|
| 192 | # a_id = Field(Integer, ForeignKey('a.id')) |
|---|
| 193 | # |
|---|
| 194 | # setup_all(True) |
|---|
| 195 | # |
|---|
| 196 | # a1 = A(name='a1', bs=[B(name='b1')]) |
|---|
| 197 | # |
|---|
| 198 | # session.commit() |
|---|
| 199 | # session.expunge_all() |
|---|
| 200 | # |
|---|
| 201 | # b = B.query.one() |
|---|
| 202 | # |
|---|
| 203 | # assert b.a_id == 1 |
|---|
| 204 | # |
|---|
| 205 | def test_inverse_has_non_pk_target(self): |
|---|
| 206 | class A(Entity): |
|---|
| 207 | name = Field(String(60), unique=True) |
|---|
| 208 | bs = OneToMany('B') |
|---|
| 209 | |
|---|
| 210 | class B(Entity): |
|---|
| 211 | name = Field(String(60)) |
|---|
| 212 | a = ManyToOne('A', target_column='name') |
|---|
| 213 | |
|---|
| 214 | setup_all(True) |
|---|
| 215 | |
|---|
| 216 | a1 = A(name='a1') |
|---|
| 217 | b1 = B(name='b1', a=a1) |
|---|
| 218 | |
|---|
| 219 | # does it work before a commit? (does the backref work?) |
|---|
| 220 | assert b1 in a1.bs |
|---|
| 221 | |
|---|
| 222 | session.commit() |
|---|
| 223 | session.expunge_all() |
|---|
| 224 | |
|---|
| 225 | b = B.query.one() |
|---|
| 226 | a = b.a |
|---|
| 227 | |
|---|
| 228 | assert b.a.name == 'a1' |
|---|
| 229 | assert b in a.bs |
|---|
| 230 | |
|---|
| 231 | def test_has_many_syntax(self): |
|---|
| 232 | class Person(Entity): |
|---|
| 233 | has_field('name', String(30)) |
|---|
| 234 | has_many('pets', of_kind='Animal') |
|---|
| 235 | |
|---|
| 236 | class Animal(Entity): |
|---|
| 237 | has_field('name', String(30)) |
|---|
| 238 | belongs_to('owner', of_kind='Person') |
|---|
| 239 | |
|---|
| 240 | setup_all(True) |
|---|
| 241 | |
|---|
| 242 | santa = Person(name="Santa Claus") |
|---|
| 243 | rudolph = Animal(name="Rudolph", owner=santa) |
|---|
| 244 | |
|---|
| 245 | session.commit() |
|---|
| 246 | session.expunge_all() |
|---|
| 247 | |
|---|
| 248 | santa = Person.get_by(name="Santa Claus") |
|---|
| 249 | |
|---|
| 250 | assert Animal.get_by(name="Rudolph") in santa.pets |
|---|