1from sqlalchemy import ForeignKey
2from sqlalchemy import Integer
3from sqlalchemy import String
4from sqlalchemy import util
5from sqlalchemy.orm import backref
6from sqlalchemy.orm import configure_mappers
7from sqlalchemy.orm import mapper
8from sqlalchemy.orm import relationship
9from sqlalchemy.testing import fixtures
10from sqlalchemy.testing.schema import Column
11from sqlalchemy.testing.schema import Table
12
13__all__ = ()
14
15
16class FixtureTest(fixtures.MappedTest):
17    """A MappedTest pre-configured with a common set of fixtures.
18
19    """
20
21    run_define_tables = "once"
22    run_setup_classes = "once"
23    run_setup_mappers = "each"
24    run_inserts = "each"
25    run_deletes = "each"
26
27    @classmethod
28    def setup_classes(cls):
29        class Base(cls.Comparable):
30            pass
31
32        class User(Base):
33            pass
34
35        class Order(Base):
36            pass
37
38        class Item(Base):
39            pass
40
41        class Keyword(Base):
42            pass
43
44        class Address(Base):
45            pass
46
47        class Dingaling(Base):
48            pass
49
50        class Node(Base):
51            pass
52
53        class CompositePk(Base):
54            pass
55
56    @classmethod
57    def _setup_stock_mapping(cls):
58        (
59            Node,
60            composite_pk_table,
61            users,
62            Keyword,
63            items,
64            Dingaling,
65            order_items,
66            item_keywords,
67            Item,
68            User,
69            dingalings,
70            Address,
71            keywords,
72            CompositePk,
73            nodes,
74            Order,
75            orders,
76            addresses,
77        ) = (
78            cls.classes.Node,
79            cls.tables.composite_pk_table,
80            cls.tables.users,
81            cls.classes.Keyword,
82            cls.tables.items,
83            cls.classes.Dingaling,
84            cls.tables.order_items,
85            cls.tables.item_keywords,
86            cls.classes.Item,
87            cls.classes.User,
88            cls.tables.dingalings,
89            cls.classes.Address,
90            cls.tables.keywords,
91            cls.classes.CompositePk,
92            cls.tables.nodes,
93            cls.classes.Order,
94            cls.tables.orders,
95            cls.tables.addresses,
96        )
97
98        # use OrderedDict on this one to support some tests that
99        # assert the order of attributes (e.g. orm/test_inspect)
100        mapper(
101            User,
102            users,
103            properties=util.OrderedDict(
104                [
105                    (
106                        "addresses",
107                        relationship(
108                            Address, backref="user", order_by=addresses.c.id
109                        ),
110                    ),
111                    (
112                        "orders",
113                        relationship(
114                            Order, backref="user", order_by=orders.c.id
115                        ),
116                    ),  # o2m, m2o
117                ]
118            ),
119        )
120        mapper(
121            Address,
122            addresses,
123            properties={
124                # o2o
125                "dingaling": relationship(
126                    Dingaling, uselist=False, backref="address"
127                )
128            },
129        )
130        mapper(Dingaling, dingalings)
131        mapper(
132            Order,
133            orders,
134            properties={
135                # m2m
136                "items": relationship(
137                    Item, secondary=order_items, order_by=items.c.id
138                ),
139                "address": relationship(Address),  # m2o
140            },
141        )
142        mapper(
143            Item,
144            items,
145            properties={
146                "keywords": relationship(
147                    Keyword, secondary=item_keywords
148                )  # m2m
149            },
150        )
151        mapper(Keyword, keywords)
152
153        mapper(
154            Node,
155            nodes,
156            properties={
157                "children": relationship(
158                    Node, backref=backref("parent", remote_side=[nodes.c.id])
159                )
160            },
161        )
162
163        mapper(CompositePk, composite_pk_table)
164
165        configure_mappers()
166
167    @classmethod
168    def define_tables(cls, metadata):
169        Table(
170            "users",
171            metadata,
172            Column(
173                "id", Integer, primary_key=True, test_needs_autoincrement=True
174            ),
175            Column("name", String(30), nullable=False),
176            test_needs_acid=True,
177            test_needs_fk=True,
178        )
179
180        Table(
181            "addresses",
182            metadata,
183            Column(
184                "id", Integer, primary_key=True, test_needs_autoincrement=True
185            ),
186            Column("user_id", None, ForeignKey("users.id")),
187            Column("email_address", String(50), nullable=False),
188            test_needs_acid=True,
189            test_needs_fk=True,
190        )
191
192        Table(
193            "email_bounces",
194            metadata,
195            Column("id", Integer, ForeignKey("addresses.id")),
196            Column("bounces", Integer),
197        )
198
199        Table(
200            "orders",
201            metadata,
202            Column(
203                "id", Integer, primary_key=True, test_needs_autoincrement=True
204            ),
205            Column("user_id", None, ForeignKey("users.id")),
206            Column("address_id", None, ForeignKey("addresses.id")),
207            Column("description", String(30)),
208            Column("isopen", Integer),
209            test_needs_acid=True,
210            test_needs_fk=True,
211        )
212
213        Table(
214            "dingalings",
215            metadata,
216            Column(
217                "id", Integer, primary_key=True, test_needs_autoincrement=True
218            ),
219            Column("address_id", None, ForeignKey("addresses.id")),
220            Column("data", String(30)),
221            test_needs_acid=True,
222            test_needs_fk=True,
223        )
224
225        Table(
226            "items",
227            metadata,
228            Column(
229                "id", Integer, primary_key=True, test_needs_autoincrement=True
230            ),
231            Column("description", String(30), nullable=False),
232            test_needs_acid=True,
233            test_needs_fk=True,
234        )
235
236        Table(
237            "order_items",
238            metadata,
239            Column("item_id", None, ForeignKey("items.id")),
240            Column("order_id", None, ForeignKey("orders.id")),
241            test_needs_acid=True,
242            test_needs_fk=True,
243        )
244
245        Table(
246            "keywords",
247            metadata,
248            Column(
249                "id", Integer, primary_key=True, test_needs_autoincrement=True
250            ),
251            Column("name", String(30), nullable=False),
252            test_needs_acid=True,
253            test_needs_fk=True,
254        )
255
256        Table(
257            "item_keywords",
258            metadata,
259            Column("item_id", None, ForeignKey("items.id")),
260            Column("keyword_id", None, ForeignKey("keywords.id")),
261            test_needs_acid=True,
262            test_needs_fk=True,
263        )
264
265        Table(
266            "nodes",
267            metadata,
268            Column(
269                "id", Integer, primary_key=True, test_needs_autoincrement=True
270            ),
271            Column("parent_id", Integer, ForeignKey("nodes.id")),
272            Column("data", String(30)),
273            test_needs_acid=True,
274            test_needs_fk=True,
275        )
276
277        Table(
278            "composite_pk_table",
279            metadata,
280            Column("i", Integer, primary_key=True),
281            Column("j", Integer, primary_key=True),
282            Column("k", Integer, nullable=False),
283        )
284
285    @classmethod
286    def setup_mappers(cls):
287        pass
288
289    @classmethod
290    def fixtures(cls):
291        return dict(
292            users=(
293                ("id", "name"),
294                (7, "jack"),
295                (8, "ed"),
296                (9, "fred"),
297                (10, "chuck"),
298            ),
299            addresses=(
300                ("id", "user_id", "email_address"),
301                (1, 7, "jack@bean.com"),
302                (2, 8, "ed@wood.com"),
303                (3, 8, "ed@bettyboop.com"),
304                (4, 8, "ed@lala.com"),
305                (5, 9, "fred@fred.com"),
306            ),
307            email_bounces=(
308                ("id", "bounces"),
309                (1, 1),
310                (2, 0),
311                (3, 5),
312                (4, 0),
313                (5, 0),
314            ),
315            orders=(
316                ("id", "user_id", "description", "isopen", "address_id"),
317                (1, 7, "order 1", 0, 1),
318                (2, 9, "order 2", 0, 4),
319                (3, 7, "order 3", 1, 1),
320                (4, 9, "order 4", 1, 4),
321                (5, 7, "order 5", 0, None),
322            ),
323            dingalings=(
324                ("id", "address_id", "data"),
325                (1, 2, "ding 1/2"),
326                (2, 5, "ding 2/5"),
327            ),
328            items=(
329                ("id", "description"),
330                (1, "item 1"),
331                (2, "item 2"),
332                (3, "item 3"),
333                (4, "item 4"),
334                (5, "item 5"),
335            ),
336            order_items=(
337                ("item_id", "order_id"),
338                (1, 1),
339                (2, 1),
340                (3, 1),
341                (1, 2),
342                (2, 2),
343                (3, 2),
344                (3, 3),
345                (4, 3),
346                (5, 3),
347                (1, 4),
348                (5, 4),
349                (5, 5),
350            ),
351            keywords=(
352                ("id", "name"),
353                (1, "blue"),
354                (2, "red"),
355                (3, "green"),
356                (4, "big"),
357                (5, "small"),
358                (6, "round"),
359                (7, "square"),
360            ),
361            item_keywords=(
362                ("keyword_id", "item_id"),
363                (2, 1),
364                (2, 2),
365                (4, 1),
366                (6, 1),
367                (5, 2),
368                (3, 3),
369                (4, 3),
370                (7, 2),
371                (6, 3),
372            ),
373            nodes=(("id", "parent_id", "data"),),
374            composite_pk_table=(
375                ("i", "j", "k"),
376                (1, 2, 3),
377                (2, 1, 4),
378                (1, 1, 5),
379                (2, 2, 6),
380            ),
381        )
382
383    @util.memoized_property
384    def static(self):
385        return CannedResults(self)
386
387
388class CannedResults(object):
389    """Built on demand, instances use mappers in effect at time of call."""
390
391    def __init__(self, test):
392        self.test = test
393
394    @property
395    def user_result(self):
396        User = self.test.classes.User
397
398        return [User(id=7), User(id=8), User(id=9), User(id=10)]
399
400    @property
401    def user_address_result(self):
402        User, Address = self.test.classes.User, self.test.classes.Address
403
404        return [
405            User(id=7, addresses=[Address(id=1)]),
406            User(
407                id=8,
408                addresses=[
409                    Address(id=2, email_address="ed@wood.com"),
410                    Address(id=3, email_address="ed@bettyboop.com"),
411                    Address(id=4, email_address="ed@lala.com"),
412                ],
413            ),
414            User(id=9, addresses=[Address(id=5)]),
415            User(id=10, addresses=[]),
416        ]
417
418    @property
419    def address_user_result(self):
420        User, Address = self.test.classes.User, self.test.classes.Address
421        u7 = User(id=7)
422        u8 = User(id=8)
423        u9 = User(id=9)
424        return [
425            Address(id=1, email_address="jack@bean.com", user=u7),
426            Address(id=2, email_address="ed@wood.com", user=u8),
427            Address(id=3, email_address="ed@bettyboop.com", user=u8),
428            Address(id=4, email_address="ed@lala.com", user=u8),
429            Address(id=5, user=u9),
430        ]
431
432    @property
433    def user_all_result(self):
434        User, Address, Order, Item = (
435            self.test.classes.User,
436            self.test.classes.Address,
437            self.test.classes.Order,
438            self.test.classes.Item,
439        )
440
441        return [
442            User(
443                id=7,
444                addresses=[Address(id=1)],
445                orders=[
446                    Order(
447                        description="order 1",
448                        items=[
449                            Item(description="item 1"),
450                            Item(description="item 2"),
451                            Item(description="item 3"),
452                        ],
453                    ),
454                    Order(description="order 3"),
455                    Order(description="order 5"),
456                ],
457            ),
458            User(
459                id=8, addresses=[Address(id=2), Address(id=3), Address(id=4)]
460            ),
461            User(
462                id=9,
463                addresses=[Address(id=5)],
464                orders=[
465                    Order(
466                        description="order 2",
467                        items=[
468                            Item(description="item 1"),
469                            Item(description="item 2"),
470                            Item(description="item 3"),
471                        ],
472                    ),
473                    Order(
474                        description="order 4",
475                        items=[
476                            Item(description="item 1"),
477                            Item(description="item 5"),
478                        ],
479                    ),
480                ],
481            ),
482            User(id=10, addresses=[]),
483        ]
484
485    @property
486    def user_order_result(self):
487        User, Order, Item = (
488            self.test.classes.User,
489            self.test.classes.Order,
490            self.test.classes.Item,
491        )
492        return [
493            User(
494                id=7,
495                orders=[
496                    Order(id=1, items=[Item(id=1), Item(id=2), Item(id=3)]),
497                    Order(id=3, items=[Item(id=3), Item(id=4), Item(id=5)]),
498                    Order(id=5, items=[Item(id=5)]),
499                ],
500            ),
501            User(id=8, orders=[]),
502            User(
503                id=9,
504                orders=[
505                    Order(id=2, items=[Item(id=1), Item(id=2), Item(id=3)]),
506                    Order(id=4, items=[Item(id=1), Item(id=5)]),
507                ],
508            ),
509            User(id=10),
510        ]
511
512    @property
513    def item_keyword_result(self):
514        Item, Keyword = self.test.classes.Item, self.test.classes.Keyword
515        return [
516            Item(
517                id=1,
518                keywords=[
519                    Keyword(name="red"),
520                    Keyword(name="big"),
521                    Keyword(name="round"),
522                ],
523            ),
524            Item(
525                id=2,
526                keywords=[
527                    Keyword(name="red"),
528                    Keyword(name="small"),
529                    Keyword(name="square"),
530                ],
531            ),
532            Item(
533                id=3,
534                keywords=[
535                    Keyword(name="green"),
536                    Keyword(name="big"),
537                    Keyword(name="round"),
538                ],
539            ),
540            Item(id=4, keywords=[]),
541            Item(id=5, keywords=[]),
542        ]
543
544    @property
545    def user_item_keyword_result(self):
546        Item, Keyword = self.test.classes.Item, self.test.classes.Keyword
547        User, Order = self.test.classes.User, self.test.classes.Order
548
549        item1, item2, item3, item4, item5 = (
550            Item(
551                id=1,
552                keywords=[
553                    Keyword(name="red"),
554                    Keyword(name="big"),
555                    Keyword(name="round"),
556                ],
557            ),
558            Item(
559                id=2,
560                keywords=[
561                    Keyword(name="red"),
562                    Keyword(name="small"),
563                    Keyword(name="square"),
564                ],
565            ),
566            Item(
567                id=3,
568                keywords=[
569                    Keyword(name="green"),
570                    Keyword(name="big"),
571                    Keyword(name="round"),
572                ],
573            ),
574            Item(id=4, keywords=[]),
575            Item(id=5, keywords=[]),
576        )
577
578        user_result = [
579            User(
580                id=7,
581                orders=[
582                    Order(id=1, items=[item1, item2, item3]),
583                    Order(id=3, items=[item3, item4, item5]),
584                    Order(id=5, items=[item5]),
585                ],
586            ),
587            User(id=8, orders=[]),
588            User(
589                id=9,
590                orders=[
591                    Order(id=2, items=[item1, item2, item3]),
592                    Order(id=4, items=[item1, item5]),
593                ],
594            ),
595            User(id=10, orders=[]),
596        ]
597        return user_result
598