Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User type performance #7574

Merged
merged 11 commits into from
Jul 7, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Create tasks for deleting order lines by deleting products or variants
- Fix doubled checkout total price for one line and zero shipping price - #7532 by @IKarbowiak
- Deprecate nested objects in TranslatableContent types - #7522 by @IKarbowiak
- Fix performance for User type on resolvers: orders, gift cards, events - #7574 by @tomaszszymanski129
- Fix failing account mutations for app - #7569 by @IKarbowiak

### Breaking
Expand Down
15 changes: 14 additions & 1 deletion saleor/graphql/account/dataloaders.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from ...account.models import Address, User
from collections import defaultdict

from ...account.models import Address, CustomerEvent, User
from ..core.dataloaders import DataLoader


Expand All @@ -16,3 +18,14 @@ class UserByUserIdLoader(DataLoader):
def batch_load(self, keys):
user_map = User.objects.in_bulk(keys)
return [user_map.get(user_id) for user_id in keys]


class CustomerEventsByUserLoader(DataLoader):
context_key = "customer_events_by_user"

def batch_load(self, keys):
events = CustomerEvent.objects.filter(user_id__in=keys)
events_by_user_map = defaultdict(list)
for event in events:
events_by_user_map[event.user_id].append(event)
return [events_by_user_map.get(user_id, []) for user_id in keys]
19 changes: 13 additions & 6 deletions saleor/graphql/account/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from ...core.exceptions import PermissionDenied
from ...core.permissions import AccountPermissions, OrderPermissions
from ...core.tracing import traced_resolver
from ...order import OrderStatus
from ...order import models as order_models
from ..checkout.dataloaders import CheckoutByUserAndChannelLoader, CheckoutByUserLoader
from ..checkout.types import Checkout
Expand All @@ -19,9 +20,12 @@
from ..core.types import CountryDisplay, Image, Permission
from ..core.utils import from_global_id_or_error, str_to_enum
from ..decorators import one_of_permissions_required, permission_required
from ..giftcard.dataloaders import GiftCardsByUserLoader
from ..meta.types import ObjectWithMetadata
from ..order.dataloaders import OrdersByUserLoader
from ..utils import format_permissions_for_display
from ..wishlist.resolvers import resolve_wishlist_items_from_user
from .dataloaders import CustomerEventsByUserLoader
from .enums import CountryCodeEnum, CustomerEventsEnum
from .utils import can_user_manage_group, get_groups_which_user_can_manage

Expand Down Expand Up @@ -303,7 +307,7 @@ def return_checkout_tokens(checkouts):
@staticmethod
@traced_resolver
def resolve_gift_cards(root: models.User, info, **_kwargs):
return root.gift_cards.all()
return GiftCardsByUserLoader(info.context).load(root.id)

@staticmethod
@traced_resolver
Expand Down Expand Up @@ -335,15 +339,18 @@ def resolve_note(root: models.User, info):
)
@traced_resolver
def resolve_events(root: models.User, info):
return root.events.all()
return CustomerEventsByUserLoader(info.context).load(root.id)

@staticmethod
@traced_resolver
def resolve_orders(root: models.User, info, **_kwargs):
viewer = info.context.user
if viewer.has_perm(OrderPermissions.MANAGE_ORDERS):
return root.orders.all()
return root.orders.non_draft() # type: ignore
def _resolve_orders(orders):
requester = info.context.user
if requester.has_perm(OrderPermissions.MANAGE_ORDERS):
return orders
tomaszszymanski129 marked this conversation as resolved.
Show resolved Hide resolved
return list(filter(lambda order: order.status != OrderStatus.DRAFT, orders))

return OrdersByUserLoader(info.context).load(root.id).then(_resolve_orders)

@staticmethod
@traced_resolver
Expand Down
15 changes: 15 additions & 0 deletions saleor/graphql/giftcard/dataloaders.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from collections import defaultdict

from ...giftcard.models import GiftCard
from ..core.dataloaders import DataLoader


class GiftCardsByUserLoader(DataLoader):
context_key = "gift_cards_by_user"

def batch_load(self, keys):
gift_cards = GiftCard.objects.filter(user_id__in=keys)
gift_cards_by_user_map = defaultdict(list)
for gift_card in gift_cards:
gift_cards_by_user_map[gift_card.user_id].append(gift_card)
return [gift_cards_by_user_map.get(user_id, []) for user_id in keys]
11 changes: 11 additions & 0 deletions saleor/graphql/order/dataloaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ def batch_load(self, keys):
return [orders.get(order_id) for order_id in keys]


class OrdersByUserLoader(DataLoader):
context_key = "order_by_user"

def batch_load(self, keys):
orders = Order.objects.filter(user_id__in=keys)
orders_by_user_map = defaultdict(list)
for order in orders:
orders_by_user_map[order.user_id].append(order)
return [orders_by_user_map.get(user_id, []) for user_id in keys]


class OrderLineByIdLoader(DataLoader):
context_key = "orderline_by_id"

Expand Down