|
6 | 6 | import graphene
|
7 | 7 | from graphene import relay
|
8 | 8 |
|
9 |
| -from ..fields import BatchSQLAlchemyConnectionField |
10 |
| -from ..types import SQLAlchemyObjectType |
| 9 | +from ..fields import (BatchSQLAlchemyConnectionField, |
| 10 | + default_connection_field_factory) |
| 11 | +from ..types import ORMField, SQLAlchemyObjectType |
11 | 12 | from .models import Article, HairKind, Pet, Reporter
|
12 | 13 | from .utils import is_sqlalchemy_version_less_than, to_std_dicts
|
13 | 14 |
|
@@ -43,19 +44,19 @@ class ReporterType(SQLAlchemyObjectType):
|
43 | 44 | class Meta:
|
44 | 45 | model = Reporter
|
45 | 46 | interfaces = (relay.Node,)
|
46 |
| - connection_field_factory = BatchSQLAlchemyConnectionField.from_relationship |
| 47 | + batching = True |
47 | 48 |
|
48 | 49 | class ArticleType(SQLAlchemyObjectType):
|
49 | 50 | class Meta:
|
50 | 51 | model = Article
|
51 | 52 | interfaces = (relay.Node,)
|
52 |
| - connection_field_factory = BatchSQLAlchemyConnectionField.from_relationship |
| 53 | + batching = True |
53 | 54 |
|
54 | 55 | class PetType(SQLAlchemyObjectType):
|
55 | 56 | class Meta:
|
56 | 57 | model = Pet
|
57 | 58 | interfaces = (relay.Node,)
|
58 |
| - connection_field_factory = BatchSQLAlchemyConnectionField.from_relationship |
| 59 | + batching = True |
59 | 60 |
|
60 | 61 | class Query(graphene.ObjectType):
|
61 | 62 | articles = graphene.Field(graphene.List(ArticleType))
|
@@ -513,3 +514,187 @@ def test_many_to_many(session_factory):
|
513 | 514 | },
|
514 | 515 | ],
|
515 | 516 | }
|
| 517 | + |
| 518 | + |
| 519 | +def test_disable_batching_via_ormfield(session_factory): |
| 520 | + session = session_factory() |
| 521 | + reporter_1 = Reporter(first_name='Reporter_1') |
| 522 | + session.add(reporter_1) |
| 523 | + reporter_2 = Reporter(first_name='Reporter_2') |
| 524 | + session.add(reporter_2) |
| 525 | + session.commit() |
| 526 | + session.close() |
| 527 | + |
| 528 | + class ReporterType(SQLAlchemyObjectType): |
| 529 | + class Meta: |
| 530 | + model = Reporter |
| 531 | + interfaces = (relay.Node,) |
| 532 | + batching = True |
| 533 | + |
| 534 | + favorite_article = ORMField(batching=False) |
| 535 | + articles = ORMField(batching=False) |
| 536 | + |
| 537 | + class ArticleType(SQLAlchemyObjectType): |
| 538 | + class Meta: |
| 539 | + model = Article |
| 540 | + interfaces = (relay.Node,) |
| 541 | + |
| 542 | + class Query(graphene.ObjectType): |
| 543 | + reporters = graphene.Field(graphene.List(ReporterType)) |
| 544 | + |
| 545 | + def resolve_reporters(self, info): |
| 546 | + return info.context.get('session').query(Reporter).all() |
| 547 | + |
| 548 | + schema = graphene.Schema(query=Query) |
| 549 | + |
| 550 | + # Test one-to-one and many-to-one relationships |
| 551 | + with mock_sqlalchemy_logging_handler() as sqlalchemy_logging_handler: |
| 552 | + # Starts new session to fully reset the engine / connection logging level |
| 553 | + session = session_factory() |
| 554 | + schema.execute(""" |
| 555 | + query { |
| 556 | + reporters { |
| 557 | + favoriteArticle { |
| 558 | + headline |
| 559 | + } |
| 560 | + } |
| 561 | + } |
| 562 | + """, context_value={"session": session}) |
| 563 | + messages = sqlalchemy_logging_handler.messages |
| 564 | + |
| 565 | + select_statements = [message for message in messages if 'SELECT' in message and 'FROM articles' in message] |
| 566 | + assert len(select_statements) == 2 |
| 567 | + |
| 568 | + # Test one-to-many and many-to-many relationships |
| 569 | + with mock_sqlalchemy_logging_handler() as sqlalchemy_logging_handler: |
| 570 | + # Starts new session to fully reset the engine / connection logging level |
| 571 | + session = session_factory() |
| 572 | + schema.execute(""" |
| 573 | + query { |
| 574 | + reporters { |
| 575 | + articles { |
| 576 | + edges { |
| 577 | + node { |
| 578 | + headline |
| 579 | + } |
| 580 | + } |
| 581 | + } |
| 582 | + } |
| 583 | + } |
| 584 | + """, context_value={"session": session}) |
| 585 | + messages = sqlalchemy_logging_handler.messages |
| 586 | + |
| 587 | + select_statements = [message for message in messages if 'SELECT' in message and 'FROM articles' in message] |
| 588 | + assert len(select_statements) == 2 |
| 589 | + |
| 590 | + |
| 591 | +def test_connection_factory_field_overrides_batching_is_false(session_factory): |
| 592 | + session = session_factory() |
| 593 | + reporter_1 = Reporter(first_name='Reporter_1') |
| 594 | + session.add(reporter_1) |
| 595 | + reporter_2 = Reporter(first_name='Reporter_2') |
| 596 | + session.add(reporter_2) |
| 597 | + session.commit() |
| 598 | + session.close() |
| 599 | + |
| 600 | + class ReporterType(SQLAlchemyObjectType): |
| 601 | + class Meta: |
| 602 | + model = Reporter |
| 603 | + interfaces = (relay.Node,) |
| 604 | + batching = False |
| 605 | + connection_field_factory = BatchSQLAlchemyConnectionField.from_relationship |
| 606 | + |
| 607 | + articles = ORMField(batching=False) |
| 608 | + |
| 609 | + class ArticleType(SQLAlchemyObjectType): |
| 610 | + class Meta: |
| 611 | + model = Article |
| 612 | + interfaces = (relay.Node,) |
| 613 | + |
| 614 | + class Query(graphene.ObjectType): |
| 615 | + reporters = graphene.Field(graphene.List(ReporterType)) |
| 616 | + |
| 617 | + def resolve_reporters(self, info): |
| 618 | + return info.context.get('session').query(Reporter).all() |
| 619 | + |
| 620 | + schema = graphene.Schema(query=Query) |
| 621 | + |
| 622 | + with mock_sqlalchemy_logging_handler() as sqlalchemy_logging_handler: |
| 623 | + # Starts new session to fully reset the engine / connection logging level |
| 624 | + session = session_factory() |
| 625 | + schema.execute(""" |
| 626 | + query { |
| 627 | + reporters { |
| 628 | + articles { |
| 629 | + edges { |
| 630 | + node { |
| 631 | + headline |
| 632 | + } |
| 633 | + } |
| 634 | + } |
| 635 | + } |
| 636 | + } |
| 637 | + """, context_value={"session": session}) |
| 638 | + messages = sqlalchemy_logging_handler.messages |
| 639 | + |
| 640 | + if is_sqlalchemy_version_less_than('1.3'): |
| 641 | + # The batched SQL statement generated is different in 1.2.x |
| 642 | + # SQLAlchemy 1.3+ optimizes out a JOIN statement in `selectin` |
| 643 | + # See https://git.io/JewQu |
| 644 | + select_statements = [message for message in messages if 'SELECT' in message and 'JOIN articles' in message] |
| 645 | + else: |
| 646 | + select_statements = [message for message in messages if 'SELECT' in message and 'FROM articles' in message] |
| 647 | + assert len(select_statements) == 1 |
| 648 | + |
| 649 | + |
| 650 | +def test_connection_factory_field_overrides_batching_is_true(session_factory): |
| 651 | + session = session_factory() |
| 652 | + reporter_1 = Reporter(first_name='Reporter_1') |
| 653 | + session.add(reporter_1) |
| 654 | + reporter_2 = Reporter(first_name='Reporter_2') |
| 655 | + session.add(reporter_2) |
| 656 | + session.commit() |
| 657 | + session.close() |
| 658 | + |
| 659 | + class ReporterType(SQLAlchemyObjectType): |
| 660 | + class Meta: |
| 661 | + model = Reporter |
| 662 | + interfaces = (relay.Node,) |
| 663 | + batching = True |
| 664 | + connection_field_factory = default_connection_field_factory |
| 665 | + |
| 666 | + articles = ORMField(batching=True) |
| 667 | + |
| 668 | + class ArticleType(SQLAlchemyObjectType): |
| 669 | + class Meta: |
| 670 | + model = Article |
| 671 | + interfaces = (relay.Node,) |
| 672 | + |
| 673 | + class Query(graphene.ObjectType): |
| 674 | + reporters = graphene.Field(graphene.List(ReporterType)) |
| 675 | + |
| 676 | + def resolve_reporters(self, info): |
| 677 | + return info.context.get('session').query(Reporter).all() |
| 678 | + |
| 679 | + schema = graphene.Schema(query=Query) |
| 680 | + |
| 681 | + with mock_sqlalchemy_logging_handler() as sqlalchemy_logging_handler: |
| 682 | + # Starts new session to fully reset the engine / connection logging level |
| 683 | + session = session_factory() |
| 684 | + schema.execute(""" |
| 685 | + query { |
| 686 | + reporters { |
| 687 | + articles { |
| 688 | + edges { |
| 689 | + node { |
| 690 | + headline |
| 691 | + } |
| 692 | + } |
| 693 | + } |
| 694 | + } |
| 695 | + } |
| 696 | + """, context_value={"session": session}) |
| 697 | + messages = sqlalchemy_logging_handler.messages |
| 698 | + |
| 699 | + select_statements = [message for message in messages if 'SELECT' in message and 'FROM articles' in message] |
| 700 | + assert len(select_statements) == 2 |
0 commit comments