|
1 | 1 | import logging |
| 2 | +from collections import defaultdict |
2 | 3 | from itertools import chain, zip_longest |
3 | 4 | from json import dumps |
4 | 5 | from typing import Dict, List |
@@ -598,75 +599,172 @@ async def test_many_to_many_load_inner_includes_to_parents( |
598 | 599 | assert ("child", ViewBase.get_db_item_id(child_4)) not in included_data |
599 | 600 |
|
600 | 601 |
|
601 | | -@mark.parametrize( |
602 | | - "include, expected_relationships", |
603 | | - [ |
604 | | - ( |
605 | | - ["posts", "posts.user"], |
606 | | - ["user"], |
607 | | - ), |
608 | | - ( |
609 | | - ["posts", "posts.comments"], |
610 | | - ["comments"], |
611 | | - ), |
612 | | - ( |
613 | | - ["posts", "posts.user", "posts.comments"], |
614 | | - ["user", "comments"], |
615 | | - ), |
616 | | - ], |
617 | | -) |
618 | | -async def test_get_users_with_posts_and_inner_includes( |
619 | | - app: FastAPI, |
620 | | - client: AsyncClient, |
621 | | - user_1: User, |
622 | | - user_2: User, |
623 | | - user_1_posts: list[PostComment], |
624 | | - user_1_post_for_comments: Post, |
625 | | - user_2_comment_for_one_u1_post: PostComment, |
626 | | - include: list[str], |
627 | | - expected_relationships: list[str], |
628 | | -): |
629 | | - """ |
630 | | - Test if requesting `posts.user` and `posts.comments` |
631 | | - returns posts with both `user` and `comments` |
632 | | - """ |
633 | | - assert user_1_posts |
634 | | - assert user_2_comment_for_one_u1_post.author_id == user_2.id |
635 | | - include_param = ",".join(include) |
636 | | - resource_type = "user" |
637 | | - url = app.url_path_for(f"get_{resource_type}_list") |
638 | | - url = f"{url}?filter[name]={user_1.name}&include={include_param}" |
639 | | - response = await client.get(url) |
640 | | - assert response.status_code == status.HTTP_200_OK, response.text |
641 | | - response_json = response.json() |
| 602 | +class TestUserWithPostsWithInnerIncludes: |
| 603 | + @mark.parametrize( |
| 604 | + "include, expected_relationships_post, case_name", |
| 605 | + [ |
| 606 | + ( |
| 607 | + ["posts", "posts.user"], |
| 608 | + ["user"], |
| 609 | + "", |
| 610 | + ), |
| 611 | + ( |
| 612 | + ["posts", "posts.comments"], |
| 613 | + ["comments"], |
| 614 | + "", |
| 615 | + ), |
| 616 | + ( |
| 617 | + ["posts", "posts.user", "posts.comments"], |
| 618 | + ["user", "comments"], |
| 619 | + "case_1", |
| 620 | + ), |
| 621 | + ( |
| 622 | + ["posts", "posts.user", "posts.comments", "posts.comments.author"], |
| 623 | + ["user", "comments"], |
| 624 | + "case_2", |
| 625 | + ), |
| 626 | + ], |
| 627 | + ) |
| 628 | + async def test_get_users_with_posts_and_inner_includes( |
| 629 | + self, |
| 630 | + app: FastAPI, |
| 631 | + client: AsyncClient, |
| 632 | + user_1: User, |
| 633 | + user_2: User, |
| 634 | + user_1_posts: list[PostComment], |
| 635 | + user_1_post_for_comments: Post, |
| 636 | + user_2_comment_for_one_u1_post: PostComment, |
| 637 | + include: list[str], |
| 638 | + expected_relationships_post: list[str], |
| 639 | + case_name: bool, |
| 640 | + ): |
| 641 | + """ |
| 642 | + Test if requesting `posts.user` and `posts.comments` |
| 643 | + returns posts with both `user` and `comments` |
| 644 | + """ |
| 645 | + assert user_1_posts |
| 646 | + assert user_2_comment_for_one_u1_post.author_id == user_2.id |
| 647 | + include_param = ",".join(include) |
| 648 | + resource_type = "user" |
| 649 | + url = app.url_path_for(f"get_{resource_type}_list") |
| 650 | + url = f"{url}?filter[name]={user_1.name}&include={include_param}" |
| 651 | + response = await client.get(url) |
| 652 | + assert response.status_code == status.HTTP_200_OK, response.text |
| 653 | + response_json = response.json() |
642 | 654 |
|
643 | | - result_data = response_json["data"] |
| 655 | + result_data = response_json["data"] |
644 | 656 |
|
645 | | - assert result_data == [ |
646 | | - { |
647 | | - "id": str(user_1.id), |
648 | | - "type": resource_type, |
649 | | - "attributes": UserAttributesBaseSchema.from_orm(user_1).dict(), |
650 | | - "relationships": { |
651 | | - "posts": { |
652 | | - "data": [ |
653 | | - # relationship info |
654 | | - {"id": str(p.id), "type": "post"} |
655 | | - # for every post |
656 | | - for p in user_1_posts |
657 | | - ], |
| 657 | + assert result_data == [ |
| 658 | + { |
| 659 | + "id": str(user_1.id), |
| 660 | + "type": resource_type, |
| 661 | + "attributes": UserAttributesBaseSchema.from_orm(user_1).dict(), |
| 662 | + "relationships": { |
| 663 | + "posts": { |
| 664 | + "data": [ |
| 665 | + # relationship info |
| 666 | + {"id": str(p.id), "type": "post"} |
| 667 | + # for every post |
| 668 | + for p in user_1_posts |
| 669 | + ], |
| 670 | + }, |
658 | 671 | }, |
659 | 672 | }, |
660 | | - }, |
661 | | - ] |
662 | | - included_data = response_json["included"] |
663 | | - |
664 | | - included_posts = [item for item in included_data if item["type"] == "post"] |
665 | | - for post in included_posts: |
666 | | - post_relationships = set(post.get("relationships", {})) |
667 | | - assert post_relationships.intersection(expected_relationships) == set( |
668 | | - expected_relationships, |
669 | | - ), f"Expected relationships {expected_relationships} not found in post {post['id']}" |
| 673 | + ] |
| 674 | + included_data = response_json["included"] |
| 675 | + |
| 676 | + included_posts = [item for item in included_data if item["type"] == "post"] |
| 677 | + for post in included_posts: |
| 678 | + post_relationships = set(post.get("relationships", {})) |
| 679 | + assert post_relationships.intersection(expected_relationships_post) == set( |
| 680 | + expected_relationships_post, |
| 681 | + ), f"Expected relationships {expected_relationships_post} not found in post {post['id']}" |
| 682 | + |
| 683 | + if not case_name: |
| 684 | + return |
| 685 | + included_as_map, expected_includes = self.prepare_expected_includes( |
| 686 | + included=included_data, |
| 687 | + user_1=user_1, |
| 688 | + user_2=user_2, |
| 689 | + user_1_posts=user_1_posts, |
| 690 | + user_2_comment_for_one_u1_post=user_2_comment_for_one_u1_post, |
| 691 | + ) |
| 692 | + |
| 693 | + if case_name == "case_2": |
| 694 | + assert "user" in expected_includes |
| 695 | + elif case_name == "case_1": |
| 696 | + expected_includes.pop("user", None) |
| 697 | + for pc in expected_includes["post_comment"]: |
| 698 | + pc.pop("relationships", None) |
| 699 | + |
| 700 | + assert included_as_map == expected_includes |
| 701 | + |
| 702 | + def prepare_expected_includes( |
| 703 | + self, |
| 704 | + included: list[dict], |
| 705 | + user_1: User, |
| 706 | + user_2: User, |
| 707 | + user_1_posts: list[PostComment], |
| 708 | + user_2_comment_for_one_u1_post: PostComment, |
| 709 | + ): |
| 710 | + included_as_map = defaultdict(list) |
| 711 | + for item in included: |
| 712 | + included_as_map[item["type"]].append(item) |
| 713 | + |
| 714 | + expected_includes = { |
| 715 | + "post": [ |
| 716 | + # |
| 717 | + { |
| 718 | + "id": str(p.id), |
| 719 | + "type": "post", |
| 720 | + "attributes": PostAttributesBaseSchema.from_orm(p).dict(), |
| 721 | + "relationships": { |
| 722 | + "user": { |
| 723 | + "data": { |
| 724 | + "id": str(user_1.id), |
| 725 | + "type": "user", |
| 726 | + }, |
| 727 | + }, |
| 728 | + "comments": { |
| 729 | + "data": [ |
| 730 | + { |
| 731 | + "id": str(user_2_comment_for_one_u1_post.id), |
| 732 | + "type": "post_comment", |
| 733 | + }, |
| 734 | + ] |
| 735 | + if p.id == user_2_comment_for_one_u1_post.post_id |
| 736 | + else [], |
| 737 | + }, |
| 738 | + }, |
| 739 | + } |
| 740 | + # |
| 741 | + for p in user_1_posts |
| 742 | + ], |
| 743 | + "post_comment": [ |
| 744 | + { |
| 745 | + "id": str(user_2_comment_for_one_u1_post.id), |
| 746 | + "type": "post_comment", |
| 747 | + "attributes": PostCommentAttributesBaseSchema.from_orm(user_2_comment_for_one_u1_post).dict(), |
| 748 | + "relationships": { |
| 749 | + "author": { |
| 750 | + "data": { |
| 751 | + "id": str(user_2.id), |
| 752 | + "type": "user", |
| 753 | + }, |
| 754 | + }, |
| 755 | + }, |
| 756 | + }, |
| 757 | + ], |
| 758 | + "user": [ |
| 759 | + { |
| 760 | + "id": str(user_2.id), |
| 761 | + "type": "user", |
| 762 | + "attributes": UserAttributesBaseSchema.from_orm(user_2).dict(), |
| 763 | + }, |
| 764 | + ], |
| 765 | + } |
| 766 | + |
| 767 | + return included_as_map, expected_includes |
670 | 768 |
|
671 | 769 |
|
672 | 770 | async def test_method_not_allowed(app: FastAPI, client: AsyncClient): |
|
0 commit comments