diff --git a/main/api/mutations/__init__.py b/main/api/mutations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main/api/mutations.py b/main/api/mutations/shop.py similarity index 95% rename from main/api/mutations.py rename to main/api/mutations/shop.py index f004e84..59deaf0 100644 --- a/main/api/mutations.py +++ b/main/api/mutations/shop.py @@ -7,7 +7,8 @@ from strawberry import ID from main import models from main.api.errors import Error, FieldError, FormErrors -from main.api.types import Order, Transaction +from main.api.types.inventory import Transaction +from main.api.types.shop import Order UserModel = get_user_model() @@ -128,3 +129,9 @@ def create_deposit(user_id: ID, amount: int) -> CreateDepositResponse: profile.save() return CreateDepositSuccess(transaction=trans) + + +@strawberry.type +class ShopMutations: + create_order = create_order + create_deposit = create_deposit diff --git a/main/api/queries/__init__.py b/main/api/queries/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main/api/queries/inventory.py b/main/api/queries/inventory.py new file mode 100644 index 0000000..6930cfa --- /dev/null +++ b/main/api/queries/inventory.py @@ -0,0 +1,9 @@ +import strawberry +import strawberry_django + +from main.api.types.inventory import Transaction, TransactionOrdering + + +@strawberry.type +class InventoryQueries: + transaction_list: list[Transaction] = strawberry_django.field(pagination=True, order=TransactionOrdering) diff --git a/main/api/queries/shop.py b/main/api/queries/shop.py new file mode 100644 index 0000000..1fe860c --- /dev/null +++ b/main/api/queries/shop.py @@ -0,0 +1,24 @@ +import strawberry +import strawberry_django + +from main import models +from main.api.types.shop import Order, OrderOrdering, OrderStats, OrderStatsByTime, Product + + +@strawberry.type +class ShopQueries: + all_products: list[Product] = strawberry_django.field() + all_orders: list[Order] = strawberry_django.field() + order_list: list[Order] = strawberry_django.field(pagination=True, order=OrderOrdering) + + @strawberry.field + def order_stats(self) -> OrderStats: + return OrderStats( + **{ + period: [ + OrderStatsByTime(**stat) + for stat in models.Order.objects.count_by_created_period(period).order_by("period") + ] + for period in ["yearly", "monthly", "daily", "hourly"] + } + ) diff --git a/main/api/queries/users.py b/main/api/queries/users.py new file mode 100644 index 0000000..ba00f72 --- /dev/null +++ b/main/api/queries/users.py @@ -0,0 +1,15 @@ +import strawberry +import strawberry_django +from django.contrib.auth.models import User as DjangoUser +from strawberry import ID + +from main.api.types.users import User + + +@strawberry.type +class UsersQueries: + all_users: list[User] = strawberry_django.field() + + @strawberry.field + def user(self, user_id: ID) -> User: + return DjangoUser.objects.get(pk=user_id) diff --git a/main/api/schema.py b/main/api/schema.py index 249a4ae..3114651 100644 --- a/main/api/schema.py +++ b/main/api/schema.py @@ -1,51 +1,19 @@ import strawberry -import strawberry_django -from django.contrib.auth.models import User as DjangoUser -from strawberry import ID -from main import models -from main.api import mutations -from main.api.types import ( - Order, - OrderOrdering, - OrderStats, - OrderStatsByTime, - Product, - Transaction, - TransactionOrdering, - User, -) +from main.api.mutations.shop import ShopMutations +from main.api.queries.inventory import InventoryQueries +from main.api.queries.shop import ShopQueries +from main.api.queries.users import UsersQueries @strawberry.type -class Query: - all_products: list[Product] = strawberry_django.field() - all_users: list[User] = strawberry_django.field() - all_orders: list[Order] = strawberry_django.field() - order_list: list[Order] = strawberry_django.field(pagination=True, order=OrderOrdering) - transaction_list: list[Transaction] = strawberry_django.field(pagination=True, order=TransactionOrdering) - - @strawberry.field - def user(self, user_id: ID) -> User: - return DjangoUser.objects.get(pk=user_id) - - @strawberry.field - def order_stats(self) -> OrderStats: - return OrderStats( - **{ - period: [ - OrderStatsByTime(**stat) - for stat in models.Order.objects.count_by_created_period(period).order_by("period") - ] - for period in ["yearly", "monthly", "daily", "hourly"] - } - ) +class Query(InventoryQueries, ShopQueries, UsersQueries): + pass @strawberry.type -class Mutation: - create_order = mutations.create_order - create_deposit = mutations.create_deposit +class Mutation(ShopMutations): + pass schema = strawberry.Schema(query=Query, mutation=Mutation) diff --git a/main/api/types.py b/main/api/types.py deleted file mode 100644 index 9986344..0000000 --- a/main/api/types.py +++ /dev/null @@ -1,115 +0,0 @@ -import json -from datetime import datetime -from typing import Any, NewType - -import strawberry -import strawberry_django -from django.contrib.auth import get_user_model -from strawberry_django import auto - -from main import models - -UserModel = get_user_model() - -JSONScalar = strawberry.scalar( - NewType("JSONScalar", Any), - serialize=lambda v: v, - parse_value=lambda v: json.loads(v), - description="The GenericScalar scalar type represents a generic GraphQL scalar value that could be: List or Object.", -) - - -@strawberry_django.filters.filter(models.Product) -class ProductFilter: - id: auto - active: auto - - -@strawberry_django.type(models.Product, filters=ProductFilter) -class Product: - id: auto - name: auto - image_url: str - sale_price_int: auto - sale_price_ext: auto - # FIXME: stricter types - user_counts: JSONScalar - - -@strawberry.type -class TopMonth: - period: str - count: int - sum: int - - -@strawberry_django.type(models.UserProfile) -class UserProfile: - id: auto - balance: auto - image: auto - last_purchase_date: datetime - order_sum_total: float - - @strawberry.field() - def top_months(self) -> list[TopMonth]: - return [TopMonth(**month) for month in self.top_months()] - - -@strawberry_django.type(UserModel) -class User: - id: auto - first_name: auto - last_name: auto - profile: UserProfile - - -@strawberry_django.ordering.order(models.Order) -class OrderOrdering: - created: auto - - -@strawberry_django.type(models.Order) -class Order: - id: auto - customer: "User" - order_sum: auto - created: auto - orderlines: list["OrderLine"] - is_external: bool - - -@strawberry_django.type(models.OrderLine) -class OrderLine: - id: auto - order: "Order" - product: "Product" - amount: auto - unit_price: auto - - -@strawberry.type -class OrderStatsByTime: - period: int - count: str - - -@strawberry.type -class OrderStats: - yearly: list[OrderStatsByTime] - monthly: list[OrderStatsByTime] - daily: list[OrderStatsByTime] - hourly: list[OrderStatsByTime] - - -@strawberry_django.ordering.order(models.Transaction) -class TransactionOrdering: - created: auto - - -@strawberry_django.type(models.Transaction) -class Transaction: - id: auto - user: "User" - amount: auto - created: auto diff --git a/main/api/types/__init__.py b/main/api/types/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/main/api/types/inventory.py b/main/api/types/inventory.py new file mode 100644 index 0000000..968dc84 --- /dev/null +++ b/main/api/types/inventory.py @@ -0,0 +1,18 @@ +import strawberry_django +from strawberry_django import auto + +from main import models +from main.api.types.users import User + + +@strawberry_django.ordering.order(models.Transaction) +class TransactionOrdering: + created: auto + + +@strawberry_django.type(models.Transaction) +class Transaction: + id: auto + user: "User" + amount: auto + created: auto diff --git a/main/api/types/shop.py b/main/api/types/shop.py new file mode 100644 index 0000000..780f238 --- /dev/null +++ b/main/api/types/shop.py @@ -0,0 +1,62 @@ +import strawberry +import strawberry_django +from strawberry_django import auto + +from main import models +from main.api.types.users import User +from main.api.types.utils import JSONScalar + + +@strawberry_django.filters.filter(models.Product) +class ProductFilter: + id: auto + active: auto + + +@strawberry_django.type(models.Product, filters=ProductFilter) +class Product: + id: auto + name: auto + image_url: str + sale_price_int: auto + sale_price_ext: auto + # FIXME: stricter types + user_counts: JSONScalar + + +@strawberry_django.ordering.order(models.Order) +class OrderOrdering: + created: auto + + +@strawberry_django.type(models.Order) +class Order: + id: auto + customer: User + order_sum: auto + created: auto + orderlines: list["OrderLine"] + is_external: bool + + +@strawberry_django.type(models.OrderLine) +class OrderLine: + id: auto + order: Order + product: Product + amount: auto + unit_price: auto + + +@strawberry.type +class OrderStatsByTime: + period: int + count: str + + +@strawberry.type +class OrderStats: + yearly: list[OrderStatsByTime] + monthly: list[OrderStatsByTime] + daily: list[OrderStatsByTime] + hourly: list[OrderStatsByTime] diff --git a/main/api/types/users.py b/main/api/types/users.py new file mode 100644 index 0000000..916a6aa --- /dev/null +++ b/main/api/types/users.py @@ -0,0 +1,38 @@ +from datetime import datetime + +import strawberry +import strawberry_django +from django.contrib.auth import get_user_model +from strawberry_django import auto + +from main import models + +UserModel = get_user_model() + + +@strawberry.type +class TopMonth: + period: str + count: int + sum: int + + +@strawberry_django.type(models.UserProfile) +class UserProfile: + id: auto + balance: auto + image: auto + last_purchase_date: datetime + order_sum_total: float + + @strawberry.field() + def top_months(self) -> list[TopMonth]: + return [TopMonth(**month) for month in self.top_months()] + + +@strawberry_django.type(UserModel) +class User: + id: auto + first_name: auto + last_name: auto + profile: UserProfile diff --git a/main/api/types/utils.py b/main/api/types/utils.py new file mode 100644 index 0000000..89a0b07 --- /dev/null +++ b/main/api/types/utils.py @@ -0,0 +1,11 @@ +import json +from typing import Any, NewType + +import strawberry + +JSONScalar = strawberry.scalar( + NewType("JSONScalar", Any), + serialize=lambda v: v, + parse_value=lambda v: json.loads(v), + description="The GenericScalar scalar type represents a generic GraphQL scalar value that could be: List or Object.", +)